diff --git a/evm_arithmetization/src/fixed_recursive_verifier.rs b/evm_arithmetization/src/fixed_recursive_verifier.rs index 2f6a639c6..1e68bc7b8 100644 --- a/evm_arithmetization/src/fixed_recursive_verifier.rs +++ b/evm_arithmetization/src/fixed_recursive_verifier.rs @@ -3064,6 +3064,28 @@ where ); let mut shrinking_wrappers = vec![]; + // When using test configurations, the initial wrapper is so simple that the + // circuit's common data cannot match the shrinking wrapper circuit's + // data. Therefore, we always add at least one shrinking wrapper here. + if threshold_degree_bits < THRESHOLD_DEGREE_BITS { + let mut builder = CircuitBuilder::new(shrinking_config.clone()); + let proof_with_pis_target = + builder.add_virtual_proof_with_pis(&initial_wrapper.circuit.common); + let last_vk = builder.constant_verifier_data(&initial_wrapper.circuit.verifier_only); + builder.verify_proof::( + &proof_with_pis_target, + &last_vk, + &initial_wrapper.circuit.common, + ); + builder.register_public_inputs(&proof_with_pis_target.public_inputs); + add_common_recursion_gates(&mut builder); + let circuit = builder.build::(); + shrinking_wrappers.push(PlonkWrapperCircuit { + circuit, + proof_with_pis_target, + }); + } + // Shrinking recursion loop. loop { let last = shrinking_wrappers diff --git a/zero/src/prover_state/circuit.rs b/zero/src/prover_state/circuit.rs index 2d8918057..44bbeeeef 100644 --- a/zero/src/prover_state/circuit.rs +++ b/zero/src/prover_state/circuit.rs @@ -5,6 +5,9 @@ use std::{ str::FromStr, }; +use evm_arithmetization::testing_utils::{ + TEST_RECURSION_CONFIG, TEST_STARK_CONFIG, TEST_THRESHOLD_DEGREE_BITS, +}; pub use evm_arithmetization::NUM_TABLES; use evm_arithmetization::{AllRecursiveCircuits, AllStark, StarkConfig}; @@ -165,6 +168,7 @@ impl From for Circuit { #[derive(Debug, Clone)] pub struct CircuitConfig { circuits: [Range; NUM_TABLES], + pub use_test_config: bool, } impl std::ops::Index for CircuitConfig { @@ -199,6 +203,7 @@ impl Default for CircuitConfig { #[cfg(feature = "cdk_erigon")] Circuit::Poseidon.default_size(), ], + use_test_config: false, } } } @@ -244,14 +249,25 @@ impl CircuitConfig { /// Build the circuits from the current config. pub fn as_all_recursive_circuits(&self) -> AllRecursiveCircuits { - AllRecursiveCircuits::new( - &AllStark::default(), - self.as_degree_bits_ranges(), - &StarkConfig::standard_fast_config(), - None, - None, - None, - ) + if self.use_test_config { + AllRecursiveCircuits::new( + &AllStark::default(), + self.as_degree_bits_ranges(), + &TEST_STARK_CONFIG, + Some(&TEST_RECURSION_CONFIG), + Some(&TEST_RECURSION_CONFIG), + Some(TEST_THRESHOLD_DEGREE_BITS), + ) + } else { + AllRecursiveCircuits::new( + &AllStark::default(), + self.as_degree_bits_ranges(), + &StarkConfig::standard_fast_config(), + None, + None, + None, + ) + } } } diff --git a/zero/src/prover_state/cli.rs b/zero/src/prover_state/cli.rs index b0bebb331..ce0457dec 100644 --- a/zero/src/prover_state/cli.rs +++ b/zero/src/prover_state/cli.rs @@ -62,6 +62,9 @@ macro_rules! gen_prover_state_config { pub persistence: CircuitPersistence, #[clap(long, help_heading = HEADING, default_value_t = TableLoadStrategy::OnDemand)] pub load_strategy: TableLoadStrategy, + /// Run with a low-security but fast STARK configuration. Enable this only for testing. + #[arg(long)] + pub use_test_config: bool, $( #[clap( @@ -108,6 +111,7 @@ impl CliProverStateConfig { .filter_map(|(circuit, range)| range.map(|range| (circuit, range))) .for_each(|(circuit, range)| config.set_circuit_size(circuit, range)); + config.use_test_config = self.use_test_config; config } diff --git a/zero/src/prover_state/mod.rs b/zero/src/prover_state/mod.rs index 8cdfb45ce..376d4c90a 100644 --- a/zero/src/prover_state/mod.rs +++ b/zero/src/prover_state/mod.rs @@ -15,6 +15,7 @@ use std::borrow::Borrow; use std::{fmt::Display, sync::OnceLock}; use clap::ValueEnum; +use evm_arithmetization::testing_utils::TEST_STARK_CONFIG; use evm_arithmetization::{ fixed_recursive_verifier::ProverOutputData, prover::prove, AllProof, AllRecursiveCircuits, AllStark, GenerationSegmentData, RecursiveCircuitsForTableSize, StarkConfig, @@ -207,20 +208,20 @@ impl ProverStateManager { &self, input: TrimmedGenerationInputs, segment_data: &mut GenerationSegmentData, + config: &StarkConfig, ) -> anyhow::Result { - let config = StarkConfig::standard_fast_config(); let all_stark = AllStark::default(); let all_proof = prove( &all_stark, - &config, + config, input, segment_data, &mut TimingTree::default(), None, )?; - let table_circuits = self.load_table_circuits(&config, &all_proof)?; + let table_circuits = self.load_table_circuits(config, &all_proof)?; let proof_with_pvs = p_state() @@ -236,10 +237,11 @@ impl ProverStateManager { &self, input: TrimmedGenerationInputs, segment_data: &mut GenerationSegmentData, + config: &StarkConfig, ) -> anyhow::Result { let p_out = p_state().state.prove_segment( &AllStark::default(), - &StarkConfig::standard_fast_config(), + config, input, segment_data, &mut TimingTree::default(), @@ -269,15 +271,20 @@ impl ProverStateManager { input: (TrimmedGenerationInputs, GenerationSegmentData), ) -> anyhow::Result { let (generation_inputs, mut segment_data) = input; + let config = if self.circuit_config.use_test_config { + TEST_STARK_CONFIG + } else { + StarkConfig::standard_fast_config() + }; match self.persistence { CircuitPersistence::None | CircuitPersistence::Disk(TableLoadStrategy::Monolithic) => { info!("using monolithic circuit {:?}", self); - self.segment_proof_monolithic(generation_inputs, &mut segment_data) + self.segment_proof_monolithic(generation_inputs, &mut segment_data, &config) } CircuitPersistence::Disk(TableLoadStrategy::OnDemand) => { info!("using on demand circuit {:?}", self); - self.segment_proof_on_demand(generation_inputs, &mut segment_data) + self.segment_proof_on_demand(generation_inputs, &mut segment_data, &config) } } }