From 943fa3b1a77becfd72a226424db08199ca706caa Mon Sep 17 00:00:00 2001 From: "sm.wu" Date: Wed, 25 Oct 2023 14:57:34 +0800 Subject: [PATCH] rw_table fingerprints equality at last chunk last row --- gadgets/src/permutation.rs | 4 +- zkevm-circuits/src/evm_circuit.rs | 254 +++--------------- zkevm-circuits/src/evm_circuit/execution.rs | 12 +- zkevm-circuits/src/evm_circuit/util.rs | 1 + .../src/evm_circuit/util/chunkctx_config.rs | 184 +++++++++++++ zkevm-circuits/src/state_circuit.rs | 4 +- zkevm-circuits/src/super_circuit.rs | 72 ++++- 7 files changed, 305 insertions(+), 226 deletions(-) create mode 100644 zkevm-circuits/src/evm_circuit/util/chunkctx_config.rs diff --git a/gadgets/src/permutation.rs b/gadgets/src/permutation.rs index 3c6e7dcbc59..db4a07959f5 100644 --- a/gadgets/src/permutation.rs +++ b/gadgets/src/permutation.rs @@ -23,8 +23,8 @@ use itertools::Itertools; /// Config for PermutationChipConfig #[derive(Clone, Debug)] pub struct PermutationChipConfig { - // column - acc_fingerprints: Column, + /// acc_fingerprints + pub acc_fingerprints: Column, row_fingerprints: Column, alpha: Column, power_of_gamma: Vec>, diff --git a/zkevm-circuits/src/evm_circuit.rs b/zkevm-circuits/src/evm_circuit.rs index 20cdd8b8098..33accf6da66 100644 --- a/zkevm-circuits/src/evm_circuit.rs +++ b/zkevm-circuits/src/evm_circuit.rs @@ -1,14 +1,9 @@ //! The EVM circuit implementation. -use gadgets::{ - is_zero::{IsZeroChip, IsZeroConfig, IsZeroInstruction}, - permutation::{PermutationChip, PermutationChipConfig}, - util::Expr, -}; +use gadgets::permutation::{PermutationChip, PermutationChipConfig}; use halo2_proofs::{ - circuit::{AssignedCell, Layouter, SimpleFloorPlanner, Value}, + circuit::{Layouter, SimpleFloorPlanner, Value}, plonk::*, - poly::Rotation, }; mod execution; @@ -21,23 +16,21 @@ pub(crate) mod util; pub(crate) mod test; #[cfg(feature = "test-circuits")] pub use self::EvmCircuit as TestEvmCircuit; -use self::{step::HasExecutionState, witness::rw::ToVec}; +use self::{ + step::HasExecutionState, util::chunkctx_config::ChunkContextConfig, witness::rw::ToVec, +}; pub use crate::witness; use crate::{ - evm_circuit::{ - param::{MAX_STEP_HEIGHT, STEP_STATE_HEIGHT}, - util::rlc, - }, + evm_circuit::param::{MAX_STEP_HEIGHT, STEP_STATE_HEIGHT}, table::{ - chunkctx_table::{ChunkCtxFieldTag, ChunkCtxTable}, - BlockTable, BytecodeTable, CopyTable, ExpTable, KeccakTable, LookupTable, RwTable, TxTable, - UXTable, + chunkctx_table::ChunkCtxTable, BlockTable, BytecodeTable, CopyTable, ExpTable, KeccakTable, + LookupTable, RwTable, TxTable, UXTable, }, util::{Challenges, SubCircuit, SubCircuitConfig}, witness::RwMap, }; -use bus_mapping::{circuit_input_builder::ChunkContext, evm::OpcodeId}; +use bus_mapping::evm::OpcodeId; use eth_types::Field; use execution::ExecutionConfig; use itertools::Itertools; @@ -61,10 +54,8 @@ pub struct EvmCircuitConfig { copy_table: CopyTable, keccak_table: KeccakTable, exp_table: ExpTable, - chunkctx_table: ChunkCtxTable, - - // rw permutation config - rw_permutation_config: PermutationChipConfig, + /// rw permutation config + pub rw_permutation_config: PermutationChipConfig, // pi for carry over previous chunk context pi_pre_continuity: Column, @@ -72,14 +63,6 @@ pub struct EvmCircuitConfig { pi_next_continuity: Column, // pi for permutation challenge pi_permutation_challenges: Column, - - // chunk context related field - chunk_index: Column, - chunk_index_next: Column, - total_chunks: Column, - q_chunk_context: Selector, - is_first_chunk: IsZeroConfig, - is_last_chunk: IsZeroConfig, } /// Circuit configuration arguments @@ -104,6 +87,13 @@ pub struct EvmCircuitConfigArgs { pub u8_table: UXTable<8>, /// U16Table pub u16_table: UXTable<16>, + /// ChunkCtxTable + pub chunkctx_table: ChunkCtxTable, + + /// is first chunk selector + pub is_first_chunk: Expression, + /// is last chunk selector + pub is_last_chunk: Expression, } impl SubCircuitConfig for EvmCircuitConfig { @@ -123,59 +113,12 @@ impl SubCircuitConfig for EvmCircuitConfig { exp_table, u8_table, u16_table, + chunkctx_table, + is_first_chunk, + is_last_chunk, }: Self::ConfigArgs, ) -> Self { - // chunk context - let chunk_index = meta.advice_column(); - let chunk_index_inv = meta.advice_column(); - let chunk_index_next = meta.advice_column(); - let chunk_diff = meta.advice_column(); - let total_chunks = meta.advice_column(); - let q_chunk_context = meta.complex_selector(); - let fixed_table = [(); 4].map(|_| meta.fixed_column()); - let chunkctx_table = ChunkCtxTable::construct(meta); - - [ - (ChunkCtxFieldTag::CurrentChunkIndex.expr(), chunk_index), - (ChunkCtxFieldTag::NextChunkIndex.expr(), chunk_index_next), - (ChunkCtxFieldTag::TotalChunks.expr(), total_chunks), - ] - .iter() - .for_each(|(tag_expr, value_col)| { - meta.lookup_any("chunk context lookup", |meta| { - let q_chunk_context = meta.query_selector(q_chunk_context); - let value_col_expr = meta.query_advice(*value_col, Rotation::cur()); - - vec![( - q_chunk_context - * rlc::expr( - &[tag_expr.clone(), value_col_expr], - challenges.lookup_input(), - ), - rlc::expr(&chunkctx_table.table_exprs(meta), challenges.lookup_input()), - )] - }); - }); - - let is_first_chunk = IsZeroChip::configure( - meta, - |meta| meta.query_selector(q_chunk_context), - |meta| meta.query_advice(chunk_index, Rotation::cur()), - chunk_index_inv, - ); - - let is_last_chunk = IsZeroChip::configure( - meta, - |meta| meta.query_selector(q_chunk_context), - |meta| { - let chunk_index = meta.query_advice(chunk_index, Rotation::cur()); - let total_chunks = meta.query_advice(total_chunks, Rotation::cur()); - - total_chunks - chunk_index - 1.expr() - }, - chunk_diff, - ); let execution = Box::new(ExecutionConfig::configure( meta, @@ -191,8 +134,8 @@ impl SubCircuitConfig for EvmCircuitConfig { &keccak_table, &exp_table, &chunkctx_table, - &is_first_chunk, - &is_last_chunk, + is_first_chunk, + is_last_chunk, )); fixed_table.iter().enumerate().for_each(|(idx, &col)| { @@ -221,9 +164,6 @@ impl SubCircuitConfig for EvmCircuitConfig { meta.enable_equality(pi_pre_continuity); meta.enable_equality(pi_next_continuity); meta.enable_equality(pi_permutation_challenges); - meta.enable_equality(chunk_index); - meta.enable_equality(chunk_index_next); - meta.enable_equality(total_chunks); Self { fixed_table, @@ -237,30 +177,14 @@ impl SubCircuitConfig for EvmCircuitConfig { copy_table, keccak_table, exp_table, - chunkctx_table, rw_permutation_config, pi_pre_continuity, pi_next_continuity, pi_permutation_challenges, - chunk_index, - chunk_index_next, - total_chunks, - is_first_chunk, - is_last_chunk, - q_chunk_context, } } } -/// chunk_index, chunk_index_next, total_chunk, initial_rwc, end_rwc -type AssignedChunkContextCell = ( - AssignedCell, - AssignedCell, - AssignedCell, - AssignedCell, - AssignedCell, -); - impl EvmCircuitConfig { /// Load fixed table pub fn load_fixed_table( @@ -284,75 +208,6 @@ impl EvmCircuitConfig { }, ) } - - /// assign chunk context - pub fn assign_chunk_context( - &self, - layouter: &mut impl Layouter, - chunk_context: &ChunkContext, - max_offset_index: usize, - ) -> Result, Error> { - let ( - chunk_index_cell, - chunk_index_next_cell, - total_chunk_cell, - initial_rwc_cell, - end_rwc_cell, - ) = self.chunkctx_table.load(layouter, chunk_context)?; - - let is_first_chunk = IsZeroChip::construct(self.is_first_chunk.clone()); - let is_last_chunk = IsZeroChip::construct(self.is_last_chunk.clone()); - layouter.assign_region( - || "chunk context", - |mut region| { - for offset in 0..max_offset_index + 1 { - self.q_chunk_context.enable(&mut region, offset)?; - - region.assign_advice( - || "chunk_index", - self.chunk_index, - offset, - || Value::known(F::from(chunk_context.chunk_index as u64)), - )?; - - region.assign_advice( - || "chunk_index_next", - self.chunk_index_next, - offset, - || Value::known(F::from(chunk_context.chunk_index as u64 + 1u64)), - )?; - - region.assign_advice( - || "total_chunks", - self.total_chunks, - offset, - || Value::known(F::from(chunk_context.total_chunks as u64)), - )?; - - is_first_chunk.assign( - &mut region, - offset, - Value::known(F::from(chunk_context.chunk_index as u64)), - )?; - is_last_chunk.assign( - &mut region, - offset, - Value::known(F::from( - (chunk_context.total_chunks - chunk_context.chunk_index - 1) as u64, - )), - )?; - } - Ok(()) - }, - )?; - Ok(( - chunk_index_cell, - chunk_index_next_cell, - total_chunk_cell, - initial_rwc_cell, - end_rwc_cell, - )) - } } /// Tx Circuit for verifying transaction signatures @@ -456,10 +311,7 @@ impl SubCircuit for EvmCircuit { config.load_fixed_table(layouter, self.fixed_table_tags.clone())?; - let max_offset_index = config.execution.assign_block(layouter, block, challenges)?; - - let (prev_chunk_index, next_chunk_index_next, total_chunks, initial_rwc, end_rwc) = - config.assign_chunk_context(layouter, &block.chunk_context, max_offset_index)?; + config.execution.assign_block(layouter, block, challenges)?; let (rw_rows_padding, _) = RwMap::table_assignments_padding( &block.rws.table_assignments(true), @@ -508,30 +360,16 @@ impl SubCircuit for EvmCircuit { layouter.constrain_instance(cell.cell(), config.pi_permutation_challenges, i) })?; // constraints prev,next fingerprints - [vec![ - prev_continuous_fingerprint_cell, - prev_chunk_index, - total_chunks.clone(), - initial_rwc, - ]] - .iter() - .flatten() - .enumerate() - .try_for_each(|(i, cell)| { - layouter.constrain_instance(cell.cell(), config.pi_pre_continuity, i) - })?; - [vec![ - next_continuous_fingerprint_cell, - next_chunk_index_next, - total_chunks, - end_rwc, - ]] - .iter() - .flatten() - .enumerate() - .try_for_each(|(i, cell)| { - layouter.constrain_instance(cell.cell(), config.pi_next_continuity, i) - })?; + layouter.constrain_instance( + prev_continuous_fingerprint_cell.cell(), + config.pi_pre_continuity, + 0, + )?; + layouter.constrain_instance( + next_continuous_fingerprint_cell.cell(), + config.pi_next_continuity, + 0, + )?; Ok(()) } @@ -539,24 +377,9 @@ impl SubCircuit for EvmCircuit { fn instance(&self) -> Vec> { let block = self.block.as_ref().unwrap(); - let (rw_table_chunked_index, rw_table_total_chunks) = ( - block.chunk_context.chunk_index, - block.chunk_context.total_chunks, - ); - vec![ - vec![ - block.permu_chronological_rwtable_prev_continuous_fingerprint, - F::from(rw_table_chunked_index as u64), - F::from(rw_table_total_chunks as u64), - F::from(block.chunk_context.initial_rwc as u64), - ], - vec![ - block.permu_chronological_rwtable_next_continuous_fingerprint, - F::from(rw_table_chunked_index as u64) + F::ONE, - F::from(rw_table_total_chunks as u64), - F::from(block.chunk_context.end_rwc as u64), - ], + vec![block.permu_chronological_rwtable_prev_continuous_fingerprint], + vec![block.permu_chronological_rwtable_next_continuous_fingerprint], vec![block.permu_alpha, block.permu_gamma], ] } @@ -670,6 +493,8 @@ impl Circuit for EvmCircuit { let u16_table = UXTable::construct(meta); let challenges = Challenges::construct(meta); let challenges_expr = challenges.exprs(meta); + let chunkctx_table = ChunkCtxTable::construct(meta); + let chunkctx_config = ChunkContextConfig::new(meta, &challenges_expr); ( EvmCircuitConfig::new( @@ -685,6 +510,9 @@ impl Circuit for EvmCircuit { exp_table, u8_table, u16_table, + chunkctx_table, + is_first_chunk: chunkctx_config.is_first_chunk.expr(), + is_last_chunk: chunkctx_config.is_last_chunk.expr(), }, ), challenges, diff --git a/zkevm-circuits/src/evm_circuit/execution.rs b/zkevm-circuits/src/evm_circuit/execution.rs index 57437ef5acd..04874c10be6 100644 --- a/zkevm-circuits/src/evm_circuit/execution.rs +++ b/zkevm-circuits/src/evm_circuit/execution.rs @@ -28,7 +28,7 @@ use crate::{ }; use bus_mapping::operation::Target; use eth_types::{evm_unimplemented, Field}; -use gadgets::{is_zero::IsZeroConfig, util::not}; +use gadgets::util::not; use halo2_proofs::{ circuit::{Layouter, Region, Value}, plonk::{ @@ -236,7 +236,7 @@ pub struct ExecutionConfig { // Selector enabled in the row where the first execution step starts. q_step_first: Selector, // Selector enabled in the row where the last execution step starts. - q_step_last: Selector, + pub q_step_last: Selector, advices: [Column; STEP_WIDTH], step: Step, pub(crate) height_map: HashMap, @@ -352,8 +352,8 @@ impl ExecutionConfig { keccak_table: &dyn LookupTable, exp_table: &dyn LookupTable, chunkctx_table: &dyn LookupTable, - is_first_chunk: &IsZeroConfig, - is_last_chunk: &IsZeroConfig, + is_first_chunk: Expression, + is_last_chunk: Expression, ) -> Self { let mut instrument = Instrument::default(); let q_usable = meta.complex_selector(); @@ -1031,7 +1031,7 @@ impl ExecutionConfig { layouter: &mut impl Layouter, block: &Block, challenges: &Challenges>, - ) -> Result { + ) -> Result<(), Error> { // Track number of calls to `layouter.assign_region` as layouter assignment passes. let mut assign_pass = 0; layouter.assign_region( @@ -1208,7 +1208,7 @@ impl ExecutionConfig { )?; assign_pass += 1; - Ok(offset) + Ok(()) }, ) } diff --git a/zkevm-circuits/src/evm_circuit/util.rs b/zkevm-circuits/src/evm_circuit/util.rs index 94cbc890f36..aa2054a0eb3 100644 --- a/zkevm-circuits/src/evm_circuit/util.rs +++ b/zkevm-circuits/src/evm_circuit/util.rs @@ -22,6 +22,7 @@ use halo2_proofs::{ use itertools::Itertools; use std::hash::{Hash, Hasher}; +pub(crate) mod chunkctx_config; pub(crate) mod common_gadget; pub(crate) mod constraint_builder; pub(crate) mod instrumentation; diff --git a/zkevm-circuits/src/evm_circuit/util/chunkctx_config.rs b/zkevm-circuits/src/evm_circuit/util/chunkctx_config.rs new file mode 100644 index 00000000000..c8c6aef7735 --- /dev/null +++ b/zkevm-circuits/src/evm_circuit/util/chunkctx_config.rs @@ -0,0 +1,184 @@ +use bus_mapping::circuit_input_builder::ChunkContext; +use gadgets::{ + is_zero::{IsZeroChip, IsZeroConfig, IsZeroInstruction}, + util::Expr, +}; +use halo2_proofs::{ + circuit::{Layouter, Value}, + plonk::{Advice, Column, ConstraintSystem, Error, Expression, Instance, Selector}, + poly::Rotation, +}; + +use crate::{ + evm_circuit::util::rlc, + table::{ + chunkctx_table::{ChunkCtxFieldTag, ChunkCtxTable}, + LookupTable, + }, +}; +use eth_types::Field; + +use super::Challenges; + +/// chunk context config +#[derive(Clone)] +pub struct ChunkContextConfig { + chunk_index: Column, + chunk_index_next: Column, + total_chunks: Column, + q_chunk_context: Selector, + pub is_first_chunk: IsZeroConfig, + pub is_last_chunk: IsZeroConfig, + + /// ChunkCtxTable + pub chunkctx_table: ChunkCtxTable, + pub pi_pre_chunkctx: Column, + pub pi_next_chunkctx: Column, +} + +impl ChunkContextConfig { + pub fn new(meta: &mut ConstraintSystem, challenges: &Challenges>) -> Self { + let q_chunk_context = meta.complex_selector(); + let chunk_index = meta.advice_column(); + let chunk_index_inv = meta.advice_column(); + let chunk_index_next = meta.advice_column(); + let chunk_diff = meta.advice_column(); + let total_chunks = meta.advice_column(); + + let pi_pre_chunkctx = meta.instance_column(); + let pi_next_chunkctx = meta.instance_column(); + meta.enable_equality(pi_pre_chunkctx); + meta.enable_equality(pi_next_chunkctx); + + let chunkctx_table = ChunkCtxTable::construct(meta); + [ + (ChunkCtxFieldTag::CurrentChunkIndex.expr(), chunk_index), + (ChunkCtxFieldTag::NextChunkIndex.expr(), chunk_index_next), + (ChunkCtxFieldTag::TotalChunks.expr(), total_chunks), + ] + .iter() + .for_each(|(tag_expr, value_col)| { + meta.lookup_any("chunk context lookup", |meta| { + let q_chunk_context = meta.query_selector(q_chunk_context); + let value_col_expr = meta.query_advice(*value_col, Rotation::cur()); + + vec![( + q_chunk_context + * rlc::expr( + &[tag_expr.clone(), value_col_expr], + challenges.lookup_input(), + ), + rlc::expr(&chunkctx_table.table_exprs(meta), challenges.lookup_input()), + )] + }); + }); + + let is_first_chunk = IsZeroChip::configure( + meta, + |meta| meta.query_selector(q_chunk_context), + |meta| meta.query_advice(chunk_index, Rotation::cur()), + chunk_index_inv, + ); + + let is_last_chunk = IsZeroChip::configure( + meta, + |meta| meta.query_selector(q_chunk_context), + |meta| { + let chunk_index = meta.query_advice(chunk_index, Rotation::cur()); + let total_chunks = meta.query_advice(total_chunks, Rotation::cur()); + + total_chunks - chunk_index - 1.expr() + }, + chunk_diff, + ); + + Self { + q_chunk_context, + chunk_index, + chunk_index_next, + total_chunks, + is_first_chunk, + is_last_chunk, + chunkctx_table, + pi_pre_chunkctx, + pi_next_chunkctx, + } + } + + /// assign chunk context + pub fn assign_chunk_context( + &self, + layouter: &mut impl Layouter, + chunk_context: &ChunkContext, + max_offset_index: usize, + ) -> Result<(), Error> { + let ( + chunk_index_cell, + chunk_index_next_cell, + total_chunk_cell, + initial_rwc_cell, + end_rwc_cell, + ) = self.chunkctx_table.load(layouter, chunk_context)?; + + let is_first_chunk = IsZeroChip::construct(self.is_first_chunk.clone()); + let is_last_chunk = IsZeroChip::construct(self.is_last_chunk.clone()); + layouter.assign_region( + || "chunk context", + |mut region| { + for offset in 0..max_offset_index + 1 { + self.q_chunk_context.enable(&mut region, offset)?; + + region.assign_advice( + || "chunk_index", + self.chunk_index, + offset, + || Value::known(F::from(chunk_context.chunk_index as u64)), + )?; + + region.assign_advice( + || "chunk_index_next", + self.chunk_index_next, + offset, + || Value::known(F::from(chunk_context.chunk_index as u64 + 1u64)), + )?; + + region.assign_advice( + || "total_chunks", + self.total_chunks, + offset, + || Value::known(F::from(chunk_context.total_chunks as u64)), + )?; + + is_first_chunk.assign( + &mut region, + offset, + Value::known(F::from(chunk_context.chunk_index as u64)), + )?; + is_last_chunk.assign( + &mut region, + offset, + Value::known(F::from( + (chunk_context.total_chunks - chunk_context.chunk_index - 1) as u64, + )), + )?; + } + Ok(()) + }, + )?; + + vec![chunk_index_cell, total_chunk_cell.clone(), initial_rwc_cell] + .iter() + .enumerate() + .try_for_each(|(i, cell)| { + layouter.constrain_instance(cell.cell(), self.pi_pre_chunkctx, i) + })?; + [chunk_index_next_cell, total_chunk_cell, end_rwc_cell] + .iter() + .enumerate() + .try_for_each(|(i, cell)| { + layouter.constrain_instance(cell.cell(), self.pi_next_chunkctx, i) + })?; + + Ok(()) + } +} diff --git a/zkevm-circuits/src/state_circuit.rs b/zkevm-circuits/src/state_circuit.rs index a6c1b071223..8bcddf78f95 100644 --- a/zkevm-circuits/src/state_circuit.rs +++ b/zkevm-circuits/src/state_circuit.rs @@ -71,8 +71,8 @@ pub struct StateCircuitConfig { // External tables mpt_table: MptTable, - // rw permutation config - rw_permutation_config: PermutationChipConfig, + /// rw permutation config + pub rw_permutation_config: PermutationChipConfig, // pi for carry over previous chunk context pi_pre_continuity: Column, diff --git a/zkevm-circuits/src/super_circuit.rs b/zkevm-circuits/src/super_circuit.rs index 9cb686c705f..bf9781da3e5 100644 --- a/zkevm-circuits/src/super_circuit.rs +++ b/zkevm-circuits/src/super_circuit.rs @@ -56,7 +56,10 @@ pub(crate) mod test; use crate::{ bytecode_circuit::{BytecodeCircuit, BytecodeCircuitConfig, BytecodeCircuitConfigArgs}, copy_circuit::{CopyCircuit, CopyCircuitConfig, CopyCircuitConfigArgs}, - evm_circuit::{EvmCircuit, EvmCircuitConfig, EvmCircuitConfigArgs}, + evm_circuit::{ + util::chunkctx_config::ChunkContextConfig, EvmCircuit, EvmCircuitConfig, + EvmCircuitConfigArgs, + }, exp_circuit::{ExpCircuit, ExpCircuitConfig}, keccak_circuit::{KeccakCircuit, KeccakCircuitConfig, KeccakCircuitConfigArgs}, pi_circuit::{PiCircuit, PiCircuitConfig, PiCircuitConfigArgs}, @@ -77,6 +80,7 @@ use eth_types::{geth_types::GethData, Field}; use halo2_proofs::{ circuit::{Layouter, SimpleFloorPlanner, Value}, plonk::{Circuit, ConstraintSystem, Error, Expression}, + poly::Rotation, }; use std::array; @@ -97,6 +101,7 @@ pub struct SuperCircuitConfig { keccak_circuit: KeccakCircuitConfig, pi_circuit: PiCircuitConfig, exp_circuit: ExpCircuitConfig, + chunkctx_config: ChunkContextConfig, } /// Circuit configuration arguments @@ -108,7 +113,6 @@ pub struct SuperCircuitConfigArgs { /// Mock randomness pub mock_randomness: F, } - impl SubCircuitConfig for SuperCircuitConfig { type ConfigArgs = SuperCircuitConfigArgs; @@ -147,6 +151,8 @@ impl SubCircuitConfig for SuperCircuitConfig { power_of_randomness[0].clone(), ); + let chunkctx_config = ChunkContextConfig::new(meta, &challenges); + let keccak_circuit = KeccakCircuitConfig::new( meta, KeccakCircuitConfigArgs { @@ -208,7 +214,7 @@ impl SubCircuitConfig for SuperCircuitConfig { let evm_circuit = EvmCircuitConfig::new( meta, EvmCircuitConfigArgs { - challenges, + challenges: challenges.clone(), tx_table, rw_table: chronological_rw_table, bytecode_table, @@ -218,6 +224,35 @@ impl SubCircuitConfig for SuperCircuitConfig { exp_table, u8_table, u16_table, + chunkctx_table: chunkctx_config.chunkctx_table.clone(), + is_first_chunk: chunkctx_config.is_first_chunk.expr(), + is_last_chunk: chunkctx_config.is_last_chunk.expr(), + }, + ); + + // constraint chronological/by address rwtable fingerprint must be the same in last chunk + // last row. + meta.create_gate( + "chronological rwtable fingerprint == by address rwtable fingerprint", + |meta| { + let is_last_chunk = chunkctx_config.is_last_chunk.expr(); + let chronological_rwtable_acc_fingerprint = meta.query_advice( + evm_circuit.rw_permutation_config.acc_fingerprints, + Rotation::cur(), + ); + let by_address_rwtable_acc_fingerprint = meta.query_advice( + state_circuit.rw_permutation_config.acc_fingerprints, + Rotation::cur(), + ); + + let q_step_last = meta.query_selector(evm_circuit.execution.q_step_last); + + vec![ + is_last_chunk + * q_step_last + * (chronological_rwtable_acc_fingerprint + - by_address_rwtable_acc_fingerprint), + ] }, ); @@ -235,6 +270,7 @@ impl SubCircuitConfig for SuperCircuitConfig { keccak_circuit, pi_circuit, exp_circuit, + chunkctx_config, } } } @@ -242,6 +278,8 @@ impl SubCircuitConfig for SuperCircuitConfig { /// The Super Circuit contains all the zkEVM circuits #[derive(Clone, Default, Debug)] pub struct SuperCircuit { + /// Block + pub block: Option>, /// EVM Circuit pub evm_circuit: EvmCircuit, /// State Circuit @@ -305,6 +343,7 @@ impl SubCircuit for SuperCircuit { let keccak_circuit = KeccakCircuit::new_from_block(block); SuperCircuit::<_> { + block: Some(block.clone()), evm_circuit, state_circuit, tx_circuit, @@ -330,6 +369,26 @@ impl SubCircuit for SuperCircuit { instance.extend_from_slice(&self.exp_circuit.instance()); instance.extend_from_slice(&self.evm_circuit.instance()); + let block = self.block.as_ref().unwrap(); + + let (rw_table_chunked_index, rw_table_total_chunks) = ( + block.chunk_context.chunk_index, + block.chunk_context.total_chunks, + ); + + instance.extend_from_slice(&[ + vec![ + F::from(rw_table_chunked_index as u64), + F::from(rw_table_total_chunks as u64), + F::from(block.chunk_context.initial_rwc as u64), + ], + vec![ + F::from(rw_table_chunked_index as u64) + F::ONE + F::ONE, + F::from(rw_table_total_chunks as u64), + F::from(block.chunk_context.end_rwc as u64), + ], + ]); + instance } @@ -376,6 +435,13 @@ impl SubCircuit for SuperCircuit { .synthesize_sub(&config.evm_circuit, challenges, layouter)?; self.pi_circuit .synthesize_sub(&config.pi_circuit, challenges, layouter)?; + + // synthesize chunk context + config.chunkctx_config.assign_chunk_context( + layouter, + &self.block.as_ref().unwrap().chunk_context, + Self::get_num_rows_required(self.block.as_ref().unwrap()), + )?; Ok(()) } }