diff --git a/book/SUMMARY.md b/book/SUMMARY.md index 4f785dd72..4f379ec2b 100644 --- a/book/SUMMARY.md +++ b/book/SUMMARY.md @@ -43,6 +43,7 @@ - [Advanced](./advanced/intro.md) - [Cost Estimator](./advanced/cost-estimator.md) + - [Prove Scripts](./advanced/prove-scripts.md) - [Reproduce Binaries](./advanced/verify-binaries.md) - [Node Setup](./advanced/node-setup.md) - [Kurtosis](./advanced/kurtosis.md) diff --git a/book/advanced/prove-scripts.md b/book/advanced/prove-scripts.md new file mode 100644 index 000000000..bfc2d8d59 --- /dev/null +++ b/book/advanced/prove-scripts.md @@ -0,0 +1,174 @@ +# Prove Scripts + +The prove scripts allow you to manually generate range and aggregation proofs for OP Succinct. + +## Overview + +OP Succinct uses a two-tier proving architecture: + +1. **Range Proofs** (`multi.rs`): Generate compressed proofs for a range of L2 blocks. These proofs verify the state transition for a specific block range. + +2. **Aggregation Proofs** (`agg.rs`): Combine multiple range proofs into a single aggregation proof. This reduces on-chain verification costs by verifying one proof instead of many. + +Both binaries use the SP1 network prover by default. + +### When to Use Aggregation + +Aggregation is useful when you need to: +- Reduce on-chain verification costs by combining multiple range proofs into one proof +- Prove larger block ranges by aggregating individual range proofs from different time periods +- Combine proofs from different proving sessions into a single proof for batch submission + +> **Note:** All range proofs must be generated in compressed mode for aggregation. The prove scripts handle this automatically. + +## Setup + +### Environment Configuration + +Create a `.env` file in the project root directory: + +```bash +# RPC Endpoints +L1_RPC= +L1_BEACON_RPC= +L2_RPC= +L2_NODE_RPC= + +# Network Prover Configuration +NETWORK_PRIVATE_KEY= + +# Proof Strategy Configuration +RANGE_PROOF_STRATEGY=reserved # Options: reserved, hosted, auction +AGG_PROOF_STRATEGY=reserved # Options: reserved, hosted, auction +AGG_PROOF_MODE=plonk # Options: plonk, groth16 +``` + +### Environment Variables + +#### Required + +| Variable | Description | +|----------|-------------| +| `L1_RPC` | L1 Archive Node endpoint | +| `L1_BEACON_RPC` | L1 Consensus (Beacon) Node endpoint | +| `L2_RPC` | L2 Execution Node (`op-geth`) endpoint | +| `L2_NODE_RPC` | L2 Rollup Node (`op-node`) endpoint | +| `NETWORK_PRIVATE_KEY` | Private key for the Succinct Prover Network. See the [Succinct Prover Network Quickstart](https://docs.succinct.xyz/docs/sp1/prover-network/quickstart) for setup instructions. | + +#### Optional + +| Variable | Description | Default | +|----------|-------------|---------| +| `RANGE_PROOF_STRATEGY` | Proof fulfillment strategy for range proofs | `reserved` | +| `AGG_PROOF_STRATEGY` | Proof fulfillment strategy for aggregation proofs | `reserved` | +| `AGG_PROOF_MODE` | Proof mode for aggregation proofs (`plonk` or `groth16`) | `plonk` | + +**Proof Strategies:** +- `reserved`: Uses reserved SP1 network capacity +- `hosted`: Uses hosted proof generation service +- `auction`: Uses auction-based proof fulfillment + +**Proof Modes:** +- `plonk`: PLONK proof system (default) +- `groth16`: Groth16 proof system + +### Getting Started with the Prover Network + +1. Follow the [Succinct Prover Network Quickstart](https://docs.succinct.xyz/docs/sp1/prover-network/quickstart) to set up your account and obtain a private key. + +2. Set the `NETWORK_PRIVATE_KEY` environment variable: + ```.env + NETWORK_PRIVATE_KEY=0x... + ``` + +3. Run the prove scripts. The binaries will automatically use the network prover with your configured key. + +## Generating Range Proofs + +The `multi.rs` binary generates compressed range proofs for a specified block range. These proofs verify the state transition function for the L2 blocks in the range. + +### Usage + +```bash +cargo run --bin multi --release -- \ + --start \ + --end \ + --prove +``` + +### Example + +```bash +# Generate a compressed range proof for blocks 1000-1300 +cargo run --bin multi --release -- \ + --start 1000 \ + --end 1300 \ + --prove +``` + +The proof will be generated in compressed mode, which is required for aggregation. + +### Output + +Range proofs are saved to `data/{chain_id}/proofs/{start_block}-{end_block}.bin` + +## Generating Aggregation Proofs + +The `agg.rs` binary aggregates multiple compressed range proofs into a single aggregation proof. This allows you to verify the state transition for a large block range with a single on-chain verification. + +### How Aggregation Works + +1. The binary loads the specified range proofs from `data/fetched_proofs/` +2. Each range proof is verified to ensure validity +3. The proofs are aggregated into a single proof that attests to the entire block range +4. The aggregation proof can be submitted on-chain for efficient verification + +### Usage + +```bash +cargo run --bin agg --release -- \ + --proofs ,, \ + --prover \ + --prove +``` + +### Example + +```bash +# Aggregate three consecutive range proofs covering blocks 1000-1900 +cargo run --bin agg --release -- \ + --proofs 1000-1300,1300-1600,1600-1900 \ + --prover 0x1234567890abcdef1234567890abcdef12345678 \ + --prove +``` + +This will generate a single aggregation proof that verifies the state transition from block 1000 to 1900. + +### Parameters + +| Parameter | Description | Required | +|-----------|-------------|----------| +| `--proofs` | Comma-separated list of proof names (without `.bin` extension) | Yes | +| `--prover` | Prover wallet address included in the aggregation proof | Yes | +| `--prove` | Generate proof (omit to only execute and verify inputs) | No | +| `--env-file` | Path to environment file (default: `.env`) | No | + +### Requirements + +- Proof files must exist in `data/fetched_proofs/` directory +- Proof names should match the range format: `{start_block}-{end_block}` +- Range proofs must be consecutive (e.g., 1000-1300, 1300-1600, 1600-1900) +- All range proofs are automatically verified before aggregation + +## Local Development + +For local development and testing, omit the `--prove` flag to execute the program without generating proofs. This allows you to verify correctness without incurring proving costs. + +```bash +# Execute without proving +cargo run --bin multi --release -- \ + --start 1000 \ + --end 1300 +``` + +This will run the full execution and report cycle counts without submitting proof requests to the network. diff --git a/scripts/prove/bin/agg.rs b/scripts/prove/bin/agg.rs index b103cba8f..b1a2baac0 100644 --- a/scripts/prove/bin/agg.rs +++ b/scripts/prove/bin/agg.rs @@ -1,15 +1,19 @@ +use std::{env, fs}; + use alloy_primitives::{Address, B256}; use anyhow::Result; use cargo_metadata::MetadataCommand; use clap::Parser; use op_succinct_client_utils::{boot::BootInfoStruct, types::u32_to_u8}; use op_succinct_elfs::AGGREGATION_ELF; -use op_succinct_host_utils::{fetcher::OPSuccinctDataFetcher, get_agg_proof_stdin}; +use op_succinct_host_utils::{ + fetcher::OPSuccinctDataFetcher, get_agg_proof_stdin, network::parse_fulfillment_strategy, +}; use op_succinct_proof_utils::get_range_elf_embedded; use sp1_sdk::{ - utils, HashableKey, Prover, ProverClient, SP1Proof, SP1ProofWithPublicValues, SP1VerifyingKey, + utils, HashableKey, Prover, ProverClient, SP1Proof, SP1ProofMode, SP1ProofWithPublicValues, + SP1VerifyingKey, }; -use std::fs; #[derive(Parser, Debug)] #[command(author, version, about, long_about = None)] @@ -63,7 +67,14 @@ fn load_aggregation_proof_data( (proofs, boot_infos) } -// Execute the OP Succinct program for a single block. +/// Aggregates multiple range proofs into a single proof. +/// +/// This binary takes multiple compressed range proofs and aggregates them into a single +/// aggregation proof. This is useful for: +/// - Reducing on-chain verification costs by combining multiple proofs into one +/// - Proving larger block ranges by aggregating individual range proofs +/// +/// Note: All input range proofs must be in compressed format for aggregation to work. #[tokio::main] async fn main() -> Result<()> { utils::setup_logger(); @@ -72,7 +83,7 @@ async fn main() -> Result<()> { dotenv::from_filename(args.env_file).ok(); - let prover = ProverClient::from_env(); + let prover = ProverClient::builder().network().build(); let fetcher = OPSuccinctDataFetcher::new_with_rollup_config().await?; let (_, vkey) = prover.setup(get_range_elf_embedded()); @@ -92,7 +103,21 @@ async fn main() -> Result<()> { println!("Aggregate ELF Verification Key: {:?}", agg_vk.vk.bytes32()); if args.prove { - prover.prove(&agg_pk, &stdin).groth16().run().expect("proving failed"); + let agg_proof_mode = + if env::var("AGG_PROOF_MODE").unwrap_or_else(|_| "plonk".to_string()).to_lowercase() == + "groth16" + { + SP1ProofMode::Groth16 + } else { + SP1ProofMode::Plonk + }; + + prover + .prove(&agg_pk, &stdin) + .mode(agg_proof_mode) + .strategy(parse_fulfillment_strategy(env::var("AGG_PROOF_STRATEGY")?)) + .run() + .expect("proving failed"); } else { let (_, report) = prover .execute(AGGREGATION_ELF, &stdin) diff --git a/scripts/prove/bin/multi.rs b/scripts/prove/bin/multi.rs index 71a1a31cd..93126fd3b 100644 --- a/scripts/prove/bin/multi.rs +++ b/scripts/prove/bin/multi.rs @@ -1,17 +1,25 @@ +use std::{env, fs, sync::Arc, time::Instant}; + use anyhow::{Context, Result}; use clap::Parser; use op_succinct_host_utils::{ block_range::get_validated_block_range, fetcher::OPSuccinctDataFetcher, host::OPSuccinctHost, - stats::ExecutionStats, witness_generation::WitnessGenerator, + network::parse_fulfillment_strategy, stats::ExecutionStats, + witness_generation::WitnessGenerator, }; use op_succinct_proof_utils::{get_range_elf_embedded, initialize_host}; use op_succinct_prove::{execute_multi, DEFAULT_RANGE}; use op_succinct_scripts::HostExecutorArgs; -use sp1_sdk::{utils, ProverClient}; -use std::{fs, sync::Arc, time::Instant}; +use sp1_sdk::{utils, Prover, ProverClient}; use tracing::debug; -/// Execute the OP Succinct program for multiple blocks. +/// Generates a compressed range proof for a block range. +/// +/// This binary generates a compressed SP1 proof that verifies the state transition +/// for a range of L2 blocks. The compressed proof format is required for aggregation. +/// +/// The proof verifies that the rollup's state transition function was correctly executed +/// for all blocks in the specified range. #[tokio::main] async fn main() -> Result<()> { let args = HostExecutorArgs::parse(); @@ -46,13 +54,20 @@ async fn main() -> Result<()> { // Get the stdin for the block. let sp1_stdin = host.witness_generator().get_sp1_stdin(witness_data)?; - let prover = ProverClient::from_env(); - if args.prove { // If the prove flag is set, generate a proof. + let prover = ProverClient::builder().network().build(); + let (pk, _) = prover.setup(get_range_elf_embedded()); - // Generate proofs in compressed mode for aggregation verification. - let proof = prover.prove(&pk, &sp1_stdin).compressed().run().unwrap(); + + // Generate a compressed range proof. Note that the compressed proof type is required + // for aggregation. + let proof = prover + .prove(&pk, &sp1_stdin) + .compressed() + .strategy(parse_fulfillment_strategy(env::var("RANGE_PROOF_STRATEGY")?)) + .run() + .unwrap(); // Create a proof directory for the chain ID if it doesn't exist. let proof_dir = format!("data/{}/proofs", data_fetcher.get_l2_chain_id().await.unwrap());