diff --git a/integration-tests/src/integration_test_circuits.rs b/integration-tests/src/integration_test_circuits.rs index 1f17cc7e6a8..b754061ce6b 100644 --- a/integration-tests/src/integration_test_circuits.rs +++ b/integration-tests/src/integration_test_circuits.rs @@ -25,27 +25,47 @@ use std::collections::HashMap; use std::sync::Mutex; use zkevm_circuits::bytecode_circuit::bytecode_unroller::BytecodeCircuit; use zkevm_circuits::copy_circuit::CopyCircuit; -use zkevm_circuits::evm_circuit::test::get_test_degree; -use zkevm_circuits::evm_circuit::{test::get_test_cicuit_from_block, witness::block_convert}; +use zkevm_circuits::evm_circuit::witness::block_convert; use zkevm_circuits::state_circuit::StateCircuit; -use zkevm_circuits::super_circuit::SuperCircuit; use zkevm_circuits::tx_circuit::TxCircuit; use zkevm_circuits::util::SubCircuit; use zkevm_circuits::witness::Block; +/// TEST_MOCK_RANDOMNESS +pub const TEST_MOCK_RANDOMNESS: u64 = 0x100; + +/// MAX_TXS +pub const MAX_TXS: usize = 4; +/// MAX_CALLDATA +pub const MAX_CALLDATA: usize = 512; +/// MAX_RWS +pub const MAX_RWS: usize = 5888; +/// MAX_BYTECODE +pub const MAX_BYTECODE: usize = 5000; +/// MAX_COPY_ROWS +pub const MAX_COPY_ROWS: usize = 5888; + const CIRCUITS_PARAMS: CircuitsParams = CircuitsParams { - max_rws: 16384, - max_txs: 4, - max_calldata: 4000, - max_bytecode: 4000, - max_copy_rows: 16384, + max_rws: MAX_RWS, + max_txs: MAX_TXS, + max_calldata: MAX_CALLDATA, + max_bytecode: MAX_BYTECODE, + max_copy_rows: MAX_COPY_ROWS, keccak_padding: None, }; -const STATE_CIRCUIT_DEGREE: u32 = 17; -const TX_CIRCUIT_DEGREE: u32 = 20; -const BYTECODE_CIRCUIT_DEGREE: u32 = 16; -const COPY_CIRCUIT_DEGREE: u32 = 16; +/// EVM Circuit degree +pub const EVM_CIRCUIT_DEGREE: u32 = 18; +/// State Circuit degree +pub const STATE_CIRCUIT_DEGREE: u32 = 17; +/// Tx Circuit degree +pub const TX_CIRCUIT_DEGREE: u32 = 20; +/// Bytecode Circuit degree +pub const BYTECODE_CIRCUIT_DEGREE: u32 = 16; +/// Copy Circuit degree +pub const COPY_CIRCUIT_DEGREE: u32 = 16; +/// Super Circuit degree +pub const SUPER_CIRCUIT_DEGREE: u32 = 20; lazy_static! { /// Data generation. @@ -61,7 +81,8 @@ lazy_static! { } lazy_static! { - static ref STATE_CIRCUIT_KEY: ProvingKey = { + /// State Circuit proving key + pub static ref STATE_CIRCUIT_KEY: ProvingKey = { let block = new_empty_block(); let circuit = StateCircuit::::new_from_block(&block); let general_params = get_general_params(STATE_CIRCUIT_DEGREE); @@ -70,7 +91,8 @@ lazy_static! { keygen_vk(&general_params, &circuit).expect("keygen_vk should not fail"); keygen_pk(&general_params, verifying_key, &circuit).expect("keygen_pk should not fail") }; - static ref TX_CIRCUIT_KEY: ProvingKey = { + /// Tx Circuit proving key + pub static ref TX_CIRCUIT_KEY: ProvingKey = { let block = new_empty_block(); let circuit = TxCircuit::::new_from_block(&block); let general_params = get_general_params(TX_CIRCUIT_DEGREE); @@ -79,7 +101,8 @@ lazy_static! { keygen_vk(&general_params, &circuit).expect("keygen_vk should not fail"); keygen_pk(&general_params, verifying_key, &circuit).expect("keygen_pk should not fail") }; - static ref BYTECODE_CIRCUIT_KEY: ProvingKey = { + /// Bytecode Circuit proving key + pub static ref BYTECODE_CIRCUIT_KEY: ProvingKey = { let block = new_empty_block(); let circuit = BytecodeCircuit::::new_from_block(&block); let general_params = get_general_params(BYTECODE_CIRCUIT_DEGREE); @@ -88,7 +111,8 @@ lazy_static! { keygen_vk(&general_params, &circuit).expect("keygen_vk should not fail"); keygen_pk(&general_params, verifying_key, &circuit).expect("keygen_pk should not fail") }; - static ref COPY_CIRCUIT_KEY: ProvingKey = { + /// Copy Circuit proving key + pub static ref COPY_CIRCUIT_KEY: ProvingKey = { let block = new_empty_block(); let circuit = CopyCircuit::::new_from_block(&block); let general_params = get_general_params(COPY_CIRCUIT_DEGREE); @@ -238,142 +262,24 @@ fn test_mock>(degree: u32, circuit: &C, instance: Vec>) { .expect("mock prover verification failed"); } -/// Integration test for evm circuit. -pub async fn test_evm_circuit_block(block_num: u64, actual: bool) { - log::info!("test evm circuit, block number: {}", block_num); - let (builder, _) = gen_inputs(block_num).await; - - let block = block_convert(&builder.block, &builder.code_db).unwrap(); - - let degree = get_test_degree(&block); - let circuit = get_test_cicuit_from_block(block); - - if actual { - test_actual(degree, circuit, vec![], None); - } else { - test_mock(degree, &circuit, vec![]); - } -} - -/// Integration test for state circuit. -pub async fn test_state_circuit_block(block_num: u64, actual: bool) { - log::info!("test state circuit, block number: {}", block_num); - +/// Integration test generic function +pub async fn test_circuit_at_block + Circuit>( + circuit_name: &str, + degree: u32, + block_num: u64, + actual: bool, + proving_key: Option>, +) { + log::info!("test {} circuit, block number: {}", circuit_name, block_num); let (builder, _) = gen_inputs(block_num).await; - let block = block_convert(&builder.block, &builder.code_db).unwrap(); - - let circuit = StateCircuit::::new_from_block(&block); + let mut block = block_convert(&builder.block, &builder.code_db).unwrap(); + block.randomness = Fr::from(TEST_MOCK_RANDOMNESS); + let circuit = C::new_from_block(&block); let instance = circuit.instance(); if actual { - test_actual( - STATE_CIRCUIT_DEGREE, - circuit, - instance, - Some((*STATE_CIRCUIT_KEY).clone()), - ); + test_actual(degree, circuit, instance, proving_key); } else { - test_mock(STATE_CIRCUIT_DEGREE, &circuit, instance); - } -} - -/// Integration test for tx circuit. -pub async fn test_tx_circuit_block(block_num: u64, actual: bool) { - log::info!("test tx circuit, block number: {}", block_num); - - let (builder, _) = gen_inputs(block_num).await; - - let block = block_convert(&builder.block, &builder.code_db).unwrap(); - let circuit = TxCircuit::::new_from_block(&block); - - if actual { - test_actual( - TX_CIRCUIT_DEGREE, - circuit, - vec![vec![]], - Some((*TX_CIRCUIT_KEY).clone()), - ); - } else { - test_mock(TX_CIRCUIT_DEGREE, &circuit, vec![vec![]]); - } -} - -/// Integration test for bytecode circuit. -pub async fn test_bytecode_circuit_block(block_num: u64, actual: bool) { - log::info!("test bytecode circuit, block number: {}", block_num); - let (builder, _) = gen_inputs(block_num).await; - - let block = block_convert(&builder.block, &builder.code_db).unwrap(); - let circuit = - BytecodeCircuit::::new_from_block_sized(&block, 2usize.pow(BYTECODE_CIRCUIT_DEGREE)); - - if actual { - test_actual( - BYTECODE_CIRCUIT_DEGREE, - circuit, - Vec::new(), - Some((*BYTECODE_CIRCUIT_KEY).clone()), - ); - } else { - test_mock(BYTECODE_CIRCUIT_DEGREE, &circuit, Vec::new()); - } -} - -/// Integration test for copy circuit. -pub async fn test_copy_circuit_block(block_num: u64, actual: bool) { - log::info!("test copy circuit, block number: {}", block_num); - let (builder, _) = gen_inputs(block_num).await; - let block = block_convert(&builder.block, &builder.code_db).unwrap(); - - let circuit = CopyCircuit::::new_from_block(&block); - - if actual { - test_actual( - COPY_CIRCUIT_DEGREE, - circuit, - vec![], - Some((*COPY_CIRCUIT_KEY).clone()), - ); - } else { - test_mock(COPY_CIRCUIT_DEGREE, &circuit, vec![]); - } -} - -/// Integration test for super circuit. -pub async fn test_super_circuit_block(block_num: u64) { - const MAX_TXS: usize = 4; - const MAX_CALLDATA: usize = 512; - const MAX_RWS: usize = 5888; - const MAX_BYTECODE: usize = 5000; - const MAX_COPY_ROWS: usize = 5888; - - log::info!("test super circuit, block number: {}", block_num); - let cli = get_client(); - let cli = BuilderClient::new( - cli, - CircuitsParams { - max_rws: MAX_RWS, - max_txs: MAX_TXS, - max_calldata: MAX_CALLDATA, - max_bytecode: MAX_BYTECODE, - max_copy_rows: MAX_COPY_ROWS, - keccak_padding: None, - }, - ) - .await - .unwrap(); - let (builder, _) = cli.gen_inputs(block_num).await.unwrap(); - let (k, circuit, instance) = - SuperCircuit::::build_from_circuit_input_builder( - &builder, - ) - .unwrap(); - // TODO: add actual prover - let prover = MockProver::run(k, &circuit, instance).unwrap(); - let res = prover.verify_par(); - if let Err(err) = res { - eprintln!("Verification failures:"); - eprintln!("{:#?}", err); - panic!("Failed verification"); + test_mock(degree, &circuit, instance); } } diff --git a/integration-tests/tests/circuits.rs b/integration-tests/tests/circuits.rs index 6702ec46db3..e014981f6de 100644 --- a/integration-tests/tests/circuits.rs +++ b/integration-tests/tests/circuits.rs @@ -5,35 +5,54 @@ macro_rules! declare_tests { async fn []() { log_init(); let block_num = GEN_DATA.blocks.get($block_tag).unwrap(); - test_evm_circuit_block(*block_num, $real_prover).await; + let pk = None; + test_circuit_at_block::>( + "evm", EVM_CIRCUIT_DEGREE, *block_num, $real_prover, pk).await; } #[tokio::test] async fn []() { log_init(); let block_num = GEN_DATA.blocks.get($block_tag).unwrap(); - test_state_circuit_block(*block_num, $real_prover).await; + let pk = if $real_prover { Some((*STATE_CIRCUIT_KEY).clone()) } else { None }; + test_circuit_at_block::> + ("state", STATE_CIRCUIT_DEGREE, *block_num, $real_prover, pk).await; } #[tokio::test] async fn []() { log_init(); let block_num = GEN_DATA.blocks.get($block_tag).unwrap(); - test_tx_circuit_block(*block_num, $real_prover).await; + let pk = if $real_prover { Some((*TX_CIRCUIT_KEY).clone()) } else { None }; + test_circuit_at_block::> + ("tx", TX_CIRCUIT_DEGREE, *block_num, $real_prover, pk).await; } #[tokio::test] async fn []() { log_init(); let block_num = GEN_DATA.blocks.get($block_tag).unwrap(); - test_bytecode_circuit_block(*block_num, $real_prover).await; + let pk = if $real_prover { Some((*BYTECODE_CIRCUIT_KEY).clone()) } else { None }; + test_circuit_at_block::> + ("bytecode", BYTECODE_CIRCUIT_DEGREE, *block_num, $real_prover, pk).await; } #[tokio::test] async fn []() { log_init(); let block_num = GEN_DATA.blocks.get($block_tag).unwrap(); - test_copy_circuit_block(*block_num, $real_prover).await; + let pk = if $real_prover { Some((*COPY_CIRCUIT_KEY).clone()) } else { None }; + test_circuit_at_block::> + ("copy", COPY_CIRCUIT_DEGREE, *block_num, $real_prover, pk).await; + } + + #[tokio::test] + async fn []() { + log_init(); + let block_num = GEN_DATA.blocks.get($block_tag).unwrap(); + let pk = None; + test_circuit_at_block::> + ("super", SUPER_CIRCUIT_DEGREE, *block_num, $real_prover, pk).await; } } }; @@ -41,25 +60,27 @@ macro_rules! declare_tests { macro_rules! unroll_tests { ($($arg:tt),*) => { + use paste::paste; + use zkevm_circuits::{ + state_circuit::StateCircuit, + super_circuit::SuperCircuit, + tx_circuit::TxCircuit, + evm_circuit::EvmCircuit, + bytecode_circuit::bytecode_unroller::BytecodeCircuit, + copy_circuit::CopyCircuit + }; + use halo2_proofs::halo2curves::bn256::Fr; + use integration_tests::integration_test_circuits::*; + use integration_tests::log_init; mod real_prover { - use paste::paste; - use integration_tests::integration_test_circuits::{ - test_bytecode_circuit_block, test_copy_circuit_block, test_evm_circuit_block, - test_state_circuit_block, test_tx_circuit_block, GEN_DATA, - }; - use integration_tests::log_init; + use super::*; $( declare_tests! ($arg, true) ; )* } mod mock_prover { - use paste::paste; - use integration_tests::integration_test_circuits::{ - test_bytecode_circuit_block, test_copy_circuit_block, test_evm_circuit_block, - test_state_circuit_block, test_tx_circuit_block, GEN_DATA, - }; - use integration_tests::log_init; + use super::*; $( declare_tests! ($arg, false) ; )* diff --git a/zkevm-circuits/src/super_circuit.rs b/zkevm-circuits/src/super_circuit.rs index f23f11e2aba..8615986a6ca 100644 --- a/zkevm-circuits/src/super_circuit.rs +++ b/zkevm-circuits/src/super_circuit.rs @@ -79,8 +79,6 @@ use halo2_proofs::{ use std::array; -/// Mock randomness used for `SuperCircuit`. -pub const MOCK_RANDOMNESS: u64 = 0x100; // TODO: Figure out if we can remove MAX_TXS, MAX_CALLDATA and MAX_RWS from the // struct. @@ -104,69 +102,22 @@ pub struct SuperCircuitConfig< exp_circuit: ExpCircuitConfig, } -/// The Super Circuit contains all the zkEVM circuits -#[derive(Clone, Default, Debug)] -pub struct SuperCircuit< - F: Field, - const MAX_TXS: usize, - const MAX_CALLDATA: usize, - const MAX_RWS: usize, - const MAX_COPY_ROWS: usize, -> { - /// EVM Circuit - pub evm_circuit: EvmCircuit, - /// State Circuit - pub state_circuit: StateCircuit, - /// The transaction circuit that will be used in the `synthesize` step. - pub tx_circuit: TxCircuit, - /// Public Input Circuit - pub pi_circuit: PiCircuit, - /// Bytecode Circuit - pub bytecode_circuit: BytecodeCircuit, - /// Copy Circuit - pub copy_circuit: CopyCircuit, - /// Exp Circuit - pub exp_circuit: ExpCircuit, - /// Keccak Circuit - pub keccak_circuit: KeccakCircuit, -} - -impl< - F: Field, - const MAX_TXS: usize, - const MAX_CALLDATA: usize, - const MAX_RWS: usize, - const MAX_COPY_ROWS: usize, - > SuperCircuit -{ - /// Return the number of rows required to verify a given block - pub fn get_num_rows_required(block: &Block) -> usize { - let num_rows_evm_circuit = { - let mut cs = ConstraintSystem::default(); - let config = Self::configure(&mut cs); - config.evm_circuit.get_num_rows_required(block) - }; - let num_rows_tx_circuit = TxCircuitConfig::::get_num_rows_required(MAX_TXS); - num_rows_evm_circuit.max(num_rows_tx_circuit) - } +/// Circuit configuration arguments +pub struct SuperCircuitConfigArgs { + /// Mock randomness + pub mock_randomness: u64, } -impl< - F: Field, - const MAX_TXS: usize, - const MAX_CALLDATA: usize, - const MAX_RWS: usize, - const MAX_COPY_ROWS: usize, - > Circuit for SuperCircuit +impl + SubCircuitConfig for SuperCircuitConfig { - type Config = SuperCircuitConfig; - type FloorPlanner = SimpleFloorPlanner; + type ConfigArgs = SuperCircuitConfigArgs; - fn without_witnesses(&self) -> Self { - Self::default() - } - - fn configure(meta: &mut ConstraintSystem) -> Self::Config { + /// Configure SuperCircuitConfig + fn new( + meta: &mut ConstraintSystem, + Self::ConfigArgs { mock_randomness }: Self::ConfigArgs, + ) -> Self { let tx_table = TxTable::construct(meta); let rw_table = RwTable::construct(meta); let mpt_table = MptTable::construct(meta); @@ -178,7 +129,7 @@ impl< let keccak_table = KeccakTable::construct(meta); let power_of_randomness: [Expression; 31] = array::from_fn(|i| { - Expression::Constant(F::from(MOCK_RANDOMNESS).pow(&[1 + i as u64, 0, 0, 0])) + Expression::Constant(F::from(mock_randomness).pow(&[1 + i as u64, 0, 0, 0])) }); let challenges = Challenges::mock( @@ -254,7 +205,7 @@ impl< }, ); - Self::Config { + Self { block_table, mpt_table, evm_circuit, @@ -267,6 +218,181 @@ impl< exp_circuit, } } +} + +/// The Super Circuit contains all the zkEVM circuits +#[derive(Clone, Default, Debug)] +pub struct SuperCircuit< + F: Field, + const MAX_TXS: usize, + const MAX_CALLDATA: usize, + const MAX_RWS: usize, + const MAX_COPY_ROWS: usize, + const MOCK_RANDOMNESS: u64, +> { + /// EVM Circuit + pub evm_circuit: EvmCircuit, + /// State Circuit + pub state_circuit: StateCircuit, + /// The transaction circuit that will be used in the `synthesize` step. + pub tx_circuit: TxCircuit, + /// Public Input Circuit + pub pi_circuit: PiCircuit, + /// Bytecode Circuit + pub bytecode_circuit: BytecodeCircuit, + /// Copy Circuit + pub copy_circuit: CopyCircuit, + /// Exp Circuit + pub exp_circuit: ExpCircuit, + /// Keccak Circuit + pub keccak_circuit: KeccakCircuit, +} + +impl< + F: Field, + const MAX_TXS: usize, + const MAX_CALLDATA: usize, + const MAX_RWS: usize, + const MAX_COPY_ROWS: usize, + const MOCK_RANDOMNESS: u64, + > SuperCircuit +{ + /// Return the number of rows required to verify a given block + pub fn get_num_rows_required(block: &Block) -> usize { + let num_rows_evm_circuit = { + let mut cs = ConstraintSystem::default(); + let config = Self::configure(&mut cs); + config.evm_circuit.get_num_rows_required(block) + }; + let num_rows_tx_circuit = TxCircuitConfig::::get_num_rows_required(MAX_TXS); + num_rows_evm_circuit.max(num_rows_tx_circuit) + } +} + +// Eventhough the SuperCircuit is not a subcircuit we implement the SubCircuit +// trait for it in order to get the `new_from_block` and `instance` methods that +// allow us to generalize integration tests. +impl< + F: Field, + const MAX_TXS: usize, + const MAX_CALLDATA: usize, + const MAX_RWS: usize, + const MAX_COPY_ROWS: usize, + const MOCK_RANDOMNESS: u64, + > SubCircuit + for SuperCircuit +{ + type Config = SuperCircuitConfig; + + fn new_from_block(block: &Block) -> Self { + let evm_circuit = EvmCircuit::new_from_block(block); + let state_circuit = StateCircuit::new_from_block(block); + let tx_circuit = TxCircuit::new_from_block(block); + let pi_circuit = PiCircuit::new_from_block(block); + let bytecode_circuit = BytecodeCircuit::new_from_block(block); + let copy_circuit = CopyCircuit::new_from_block_no_external(&block); + let exp_circuit = ExpCircuit::new_from_block(block); + let keccak_circuit = KeccakCircuit::new_from_block(block); + + SuperCircuit::<_, MAX_TXS, MAX_CALLDATA, MAX_RWS, MAX_COPY_ROWS, MOCK_RANDOMNESS> { + evm_circuit, + state_circuit, + tx_circuit, + pi_circuit, + bytecode_circuit, + copy_circuit, + exp_circuit, + keccak_circuit, + } + } + + /// Returns suitable inputs for the SuperCircuit. + fn instance(&self) -> Vec> { + let mut instance = Vec::new(); + instance.extend_from_slice(&self.keccak_circuit.instance()); + instance.extend_from_slice(&self.pi_circuit.instance()); + instance.extend_from_slice(&self.tx_circuit.instance()); + instance.extend_from_slice(&self.bytecode_circuit.instance()); + instance.extend_from_slice(&self.copy_circuit.instance()); + instance.extend_from_slice(&self.state_circuit.instance()); + instance.extend_from_slice(&self.exp_circuit.instance()); + instance.extend_from_slice(&self.evm_circuit.instance()); + + instance + } + + /// Return the minimum number of rows required to prove the block + fn min_num_rows_block(block: &Block) -> (usize, usize) { + let evm = EvmCircuit::min_num_rows_block(block); + let state = StateCircuit::min_num_rows_block(block); + let bytecode = BytecodeCircuit::min_num_rows_block(block); + let copy = CopyCircuit::min_num_rows_block(block); + let keccak = KeccakCircuit::min_num_rows_block(block); + let tx = TxCircuit::min_num_rows_block(block); + let exp = ExpCircuit::min_num_rows_block(block); + let pi = PiCircuit::min_num_rows_block(block); + + let rows: Vec<(usize, usize)> = vec![evm, state, bytecode, copy, keccak, tx, exp, pi]; + let (rows_without_padding, rows_with_padding): (Vec, Vec) = + rows.into_iter().unzip(); + ( + itertools::max(rows_without_padding).unwrap(), + itertools::max(rows_with_padding).unwrap(), + ) + } + + /// Make the assignments to the SuperCircuit + fn synthesize_sub( + &self, + config: &Self::Config, + challenges: &Challenges>, + layouter: &mut impl Layouter, + ) -> Result<(), Error> { + self.keccak_circuit + .synthesize_sub(&config.keccak_circuit, &challenges, layouter)?; + self.bytecode_circuit + .synthesize_sub(&config.bytecode_circuit, &challenges, layouter)?; + self.tx_circuit + .synthesize_sub(&config.tx_circuit, &challenges, layouter)?; + self.state_circuit + .synthesize_sub(&config.state_circuit, &challenges, layouter)?; + self.copy_circuit + .synthesize_sub(&config.copy_circuit, &challenges, layouter)?; + self.exp_circuit + .synthesize_sub(&config.exp_circuit, &challenges, layouter)?; + self.evm_circuit + .synthesize_sub(&config.evm_circuit, &challenges, layouter)?; + self.pi_circuit + .synthesize_sub(&config.pi_circuit, &challenges, layouter)?; + Ok(()) + } +} + +impl< + F: Field, + const MAX_TXS: usize, + const MAX_CALLDATA: usize, + const MAX_RWS: usize, + const MAX_COPY_ROWS: usize, + const MOCK_RANDOMNESS: u64, + > Circuit + for SuperCircuit +{ + type Config = SuperCircuitConfig; + type FloorPlanner = SimpleFloorPlanner; + + fn without_witnesses(&self) -> Self { + Self::default() + } + + fn configure(meta: &mut ConstraintSystem) -> Self::Config { + Self::Config::new( + meta, + SuperCircuitConfigArgs { + mock_randomness: MOCK_RANDOMNESS, + }, + ) + } fn synthesize( &self, @@ -293,26 +419,7 @@ impl< Value::known(block.randomness), )?; - self.keccak_circuit - .synthesize_sub(&config.keccak_circuit, &challenges, &mut layouter)?; - self.bytecode_circuit.synthesize_sub( - &config.bytecode_circuit, - &challenges, - &mut layouter, - )?; - self.tx_circuit - .synthesize_sub(&config.tx_circuit, &challenges, &mut layouter)?; - self.state_circuit - .synthesize_sub(&config.state_circuit, &challenges, &mut layouter)?; - self.copy_circuit - .synthesize_sub(&config.copy_circuit, &challenges, &mut layouter)?; - self.exp_circuit - .synthesize_sub(&config.exp_circuit, &challenges, &mut layouter)?; - self.evm_circuit - .synthesize_sub(&config.evm_circuit, &challenges, &mut layouter)?; - self.pi_circuit - .synthesize_sub(&config.pi_circuit, &challenges, &mut layouter)?; - Ok(()) + self.synthesize_sub(&config, &challenges, &mut layouter) } } @@ -322,7 +429,8 @@ impl< const MAX_CALLDATA: usize, const MAX_RWS: usize, const MAX_COPY_ROWS: usize, - > SuperCircuit + const MOCK_RANDOMNESS: u64, + > SuperCircuit { /// From the witness data, generate a SuperCircuit instance with all of the /// sub-circuits filled with their corresponding witnesses. @@ -369,58 +477,18 @@ impl< let k = log2_ceil(NUM_BLINDING_ROWS + rows_needed); log::debug!("super circuit uses k = {}", k); - let evm_circuit = EvmCircuit::new_from_block(&block); - let state_circuit = StateCircuit::new_from_block(&block); - let tx_circuit = TxCircuit::new_from_block(&block); - let pi_circuit = PiCircuit::new_from_block(&block); - let bytecode_circuit = BytecodeCircuit::new_from_block(&block); - let copy_circuit = CopyCircuit::new_from_block_no_external(&block); - let exp_circuit = ExpCircuit::new_from_block(&block); - let keccak_circuit = KeccakCircuit::new_from_block(&block); - - let circuit = SuperCircuit::<_, MAX_TXS, MAX_CALLDATA, MAX_RWS, MAX_COPY_ROWS> { - evm_circuit, - state_circuit, - tx_circuit, - pi_circuit, - bytecode_circuit, - copy_circuit, - exp_circuit, - keccak_circuit, - }; + let circuit = SuperCircuit::< + _, + MAX_TXS, + MAX_CALLDATA, + MAX_RWS, + MAX_COPY_ROWS, + MOCK_RANDOMNESS, + >::new_from_block(&block); let instance = circuit.instance(); Ok((k, circuit, instance)) } - - /// Returns suitable inputs for the SuperCircuit. - pub fn instance(&self) -> Vec> { - // SignVerifyChip -> ECDSAChip -> MainGate instance column - let pi_instance = self.pi_circuit.instance(); - let instance = vec![pi_instance[0].clone(), vec![]]; - - instance - } - - /// Return the minimum number of rows required to prove the block - pub fn min_num_rows_block(block: &Block) -> (usize, usize) { - let evm = EvmCircuit::min_num_rows_block(block); - let state = StateCircuit::min_num_rows_block(block); - let bytecode = BytecodeCircuit::min_num_rows_block(block); - let copy = CopyCircuit::min_num_rows_block(block); - let keccak = KeccakCircuit::min_num_rows_block(block); - let tx = TxCircuit::min_num_rows_block(block); - let exp = ExpCircuit::min_num_rows_block(block); - let pi = PiCircuit::min_num_rows_block(block); - - let rows: Vec<(usize, usize)> = vec![evm, state, bytecode, copy, keccak, tx, exp, pi]; - let (rows_without_padding, rows_with_padding): (Vec, Vec) = - rows.into_iter().unzip(); - ( - itertools::max(rows_without_padding).unwrap(), - itertools::max(rows_with_padding).unwrap(), - ) - } } #[cfg(test)] @@ -440,7 +508,7 @@ mod super_circuit_tests { #[test] fn super_circuit_degree() { let mut cs = ConstraintSystem::::default(); - SuperCircuit::<_, 1, 32, 256, 32>::configure(&mut cs); + SuperCircuit::<_, 1, 32, 256, 32, 0x100>::configure(&mut cs); log::info!("super circuit degree: {}", cs.degree()); log::info!("super circuit minimum_rows: {}", cs.minimum_rows()); assert!(cs.degree() <= 9); @@ -451,12 +519,19 @@ mod super_circuit_tests { const MAX_CALLDATA: usize, const MAX_RWS: usize, const MAX_COPY_ROWS: usize, + const MOCK_RANDOMNESS: u64, >( block: GethData, ) { - let (k, circuit, instance, _) = - SuperCircuit::::build(block) - .unwrap(); + let (k, circuit, instance, _) = SuperCircuit::< + Fr, + MAX_TXS, + MAX_CALLDATA, + MAX_RWS, + MAX_COPY_ROWS, + MOCK_RANDOMNESS, + >::build(block) + .unwrap(); let prover = MockProver::run(k, &circuit, instance).unwrap(); let res = prover.verify_par(); if let Err(err) = res { @@ -551,6 +626,8 @@ mod super_circuit_tests { block } + const TEST_MOCK_RANDOMNESS: u64 = 0x100; + // High memory usage test. Run in serial with: // `cargo test [...] serial_ -- --ignored --test-threads 1` #[ignore] @@ -561,7 +638,9 @@ mod super_circuit_tests { const MAX_CALLDATA: usize = 32; const MAX_RWS: usize = 256; const MAX_COPY_ROWS: usize = 256; - test_super_circuit::(block); + test_super_circuit::( + block, + ); } #[ignore] #[test] @@ -571,7 +650,9 @@ mod super_circuit_tests { const MAX_CALLDATA: usize = 32; const MAX_RWS: usize = 256; const MAX_COPY_ROWS: usize = 256; - test_super_circuit::(block); + test_super_circuit::( + block, + ); } #[ignore] #[test] @@ -581,6 +662,8 @@ mod super_circuit_tests { const MAX_CALLDATA: usize = 32; const MAX_RWS: usize = 256; const MAX_COPY_ROWS: usize = 256; - test_super_circuit::(block); + test_super_circuit::( + block, + ); } } diff --git a/zkevm-circuits/src/tx_circuit.rs b/zkevm-circuits/src/tx_circuit.rs index c8de88e68ec..09e6d98f7d0 100644 --- a/zkevm-circuits/src/tx_circuit.rs +++ b/zkevm-circuits/src/tx_circuit.rs @@ -374,6 +374,12 @@ impl SubCircuit for TxCircuit { self.assign_tx_table(config, challenges, layouter, assigned_sig_verifs)?; Ok(()) } + + fn instance(&self) -> Vec> { + // The maingate expects an instance column, but we don't use it, so we return an + // "empty" instance column + vec![vec![]] + } } #[cfg(any(feature = "test", test))]