From c3d2c2bfbfd338dad012fc5950c37023325a9d5a Mon Sep 17 00:00:00 2001 From: "sm.wu" Date: Mon, 22 May 2023 22:36:28 +0800 Subject: [PATCH] refactor evm/state circuit to share range check --- zkevm-circuits/src/evm_circuit.rs | 64 ++++++--------------- zkevm-circuits/src/evm_circuit/execution.rs | 2 + zkevm-circuits/src/evm_circuit/util.rs | 1 + zkevm-circuits/src/state_circuit.rs | 15 ++++- zkevm-circuits/src/state_circuit/dev.rs | 7 +++ zkevm-circuits/src/state_circuit/lookups.rs | 44 ++++++-------- zkevm-circuits/src/super_circuit.rs | 21 ++++++- zkevm-circuits/src/table.rs | 46 +++++++++++++++ 8 files changed, 125 insertions(+), 75 deletions(-) diff --git a/zkevm-circuits/src/evm_circuit.rs b/zkevm-circuits/src/evm_circuit.rs index 10ca0485e7c..a7b9d740b1e 100644 --- a/zkevm-circuits/src/evm_circuit.rs +++ b/zkevm-circuits/src/evm_circuit.rs @@ -21,7 +21,8 @@ pub use crate::witness; use crate::{ evm_circuit::param::{MAX_STEP_HEIGHT, STEP_STATE_HEIGHT}, table::{ - BlockTable, BytecodeTable, CopyTable, ExpTable, KeccakTable, LookupTable, RwTable, TxTable, + BlockTable, BytecodeTable, CopyTable, ExpTable, KeccakTable, LookupTable, MaxNBitTable, + RwTable, TxTable, }, util::{Challenges, SubCircuit, SubCircuitConfig}, }; @@ -37,8 +38,8 @@ use witness::Block; #[derive(Clone, Debug)] pub struct EvmCircuitConfig { fixed_table: [Column; 4], - u8_table: [Column; 1], // byte table - u16_table: [Column; 1], // 2 bytes table. + u8_table: MaxNBitTable<8>, + u16_table: MaxNBitTable<16>, pub(crate) execution: Box>, // External tables tx_table: TxTable, @@ -68,6 +69,10 @@ pub struct EvmCircuitConfigArgs { pub keccak_table: KeccakTable, /// ExpTable pub exp_table: ExpTable, + /// U8Table + pub u8_table: MaxNBitTable<8>, + /// U16Table + pub u16_table: MaxNBitTable<16>, } impl SubCircuitConfig for EvmCircuitConfig { @@ -86,11 +91,11 @@ impl SubCircuitConfig for EvmCircuitConfig { copy_table, keccak_table, exp_table, + u8_table, + u16_table, }: Self::ConfigArgs, ) -> Self { let fixed_table = [(); 4].map(|_| meta.fixed_column()); - let u8_table = [(); 1].map(|_| meta.fixed_column()); - let u16_table = [(); 1].map(|_| meta.fixed_column()); let execution = Box::new(ExecutionConfig::configure( meta, challenges, @@ -118,6 +123,8 @@ impl SubCircuitConfig for EvmCircuitConfig { copy_table.annotate_columns(meta); keccak_table.annotate_columns(meta); exp_table.annotate_columns(meta); + u8_table.annotate_columns(meta); + u16_table.annotate_columns(meta); Self { fixed_table, @@ -158,44 +165,6 @@ impl EvmCircuitConfig { }, ) } - - /// Load u8 table - pub fn load_u8_table(&self, layouter: &mut impl Layouter) -> Result<(), Error> { - layouter.assign_region( - || "u8 table", - |mut region| { - for offset in 0..(1 << 8) { - region.assign_fixed( - || "", - self.u8_table[0], - offset, - || Value::known(F::from(offset as u64)), - )?; - } - - Ok(()) - }, - ) - } - - /// Load u16 table - pub fn load_u16_table(&self, layouter: &mut impl Layouter) -> Result<(), Error> { - layouter.assign_region( - || "u16 table", - |mut region| { - for offset in 0..(1 << 16) { - region.assign_fixed( - || "", - self.u16_table[0], - offset, - || Value::known(F::from(offset as u64)), - )?; - } - - Ok(()) - }, - ) - } } /// Tx Circuit for verifying transaction signatures @@ -294,8 +263,6 @@ impl SubCircuit for EvmCircuit { let block = self.block.as_ref().unwrap(); config.load_fixed_table(layouter, self.fixed_table_tags.clone())?; - config.load_u8_table(layouter)?; - config.load_u16_table(layouter)?; config.execution.assign_block(layouter, block, challenges) } } @@ -398,6 +365,8 @@ impl Circuit for EvmCircuit { let copy_table = CopyTable::construct(meta, q_copy_table); let keccak_table = KeccakTable::construct(meta); let exp_table = ExpTable::construct(meta); + let u8_table = MaxNBitTable::construct(meta); + let u16_table = MaxNBitTable::construct(meta); let challenges = Challenges::construct(meta); let challenges_expr = challenges.exprs(meta); @@ -413,6 +382,8 @@ impl Circuit for EvmCircuit { copy_table, keccak_table, exp_table, + u8_table, + u16_table, }, ), challenges, @@ -455,6 +426,9 @@ impl Circuit for EvmCircuit { .dev_load(&mut layouter, &block.sha3_inputs, &challenges)?; config.exp_table.load(&mut layouter, block)?; + config.u8_table.load(&mut layouter); + config.u16_table.load(&mut layouter); + self.synthesize_sub(&config, &challenges, &mut layouter) } } diff --git a/zkevm-circuits/src/evm_circuit/execution.rs b/zkevm-circuits/src/evm_circuit/execution.rs index cb9679d125f..9b1e8e34fc2 100644 --- a/zkevm-circuits/src/evm_circuit/execution.rs +++ b/zkevm-circuits/src/evm_circuit/execution.rs @@ -836,6 +836,7 @@ impl ExecutionConfig { for column in cell_manager.columns().iter() { if let CellType::LookupU8 = column.cell_type { meta.lookup_any("u8 lookup", |meta| { + debug_assert_eq!(u8_table.table_exprs(meta).len(), 1); let u8_table_expression = u8_table.table_exprs(meta)[0].clone(); vec![(column.expr(), u8_table_expression)] }); @@ -843,6 +844,7 @@ impl ExecutionConfig { } for column in cell_manager.columns().iter() { if let CellType::LookupU16 = column.cell_type { + debug_assert_eq!(u16_table.table_exprs(meta).len(), 1); meta.lookup_any("u16 lookup", |meta| { let u16_table_expression = u16_table.table_exprs(meta)[0].clone(); vec![(column.expr(), u16_table_expression)] diff --git a/zkevm-circuits/src/evm_circuit/util.rs b/zkevm-circuits/src/evm_circuit/util.rs index 384ffe79187..1fe8232617a 100644 --- a/zkevm-circuits/src/evm_circuit/util.rs +++ b/zkevm-circuits/src/evm_circuit/util.rs @@ -276,6 +276,7 @@ pub(crate) enum CellType { StoragePhase1, StoragePhase2, StoragePermutation, + // TODO combine LookupU8, LookupU16 with Lookup(Table::U8 | Table::U16) LookupU8, LookupU16, Lookup(Table), diff --git a/zkevm-circuits/src/state_circuit.rs b/zkevm-circuits/src/state_circuit.rs index 0270ca098d0..bb6cab8b411 100644 --- a/zkevm-circuits/src/state_circuit.rs +++ b/zkevm-circuits/src/state_circuit.rs @@ -19,7 +19,9 @@ use self::{ }; use crate::{ evm_circuit::{param::N_BYTES_WORD, util::rlc}, - table::{AccountFieldTag, LookupTable, MPTProofType, MptTable, RwTable, RwTableTag}, + table::{ + AccountFieldTag, LookupTable, MPTProofType, MaxNBitTable, MptTable, RwTable, RwTableTag, + }, util::{Challenges, Expr, SubCircuit, SubCircuitConfig}, witness::{self, MptUpdates, Rw, RwMap}, }; @@ -79,6 +81,12 @@ pub struct StateCircuitConfigArgs { pub rw_table: RwTable, /// MptTable pub mpt_table: MptTable, + /// U8Table + u8_table: MaxNBitTable<8>, + /// U10Table + u10_table: MaxNBitTable<10>, + /// U16Table + u16_table: MaxNBitTable<16>, /// Challenges pub challenges: Challenges>, } @@ -92,11 +100,14 @@ impl SubCircuitConfig for StateCircuitConfig { Self::ConfigArgs { rw_table, mpt_table, + u8_table, + u10_table, + u16_table, challenges, }: Self::ConfigArgs, ) -> Self { let selector = meta.fixed_column(); - let lookups = LookupsChip::configure(meta); + let lookups = LookupsChip::configure(meta, u8_table, u10_table, u16_table); let power_of_randomness: [Expression; 31] = challenges.evm_word_powers_of_randomness(); let rw_counter = MpiChip::configure(meta, selector, rw_table.rw_counter, lookups); diff --git a/zkevm-circuits/src/state_circuit/dev.rs b/zkevm-circuits/src/state_circuit/dev.rs index db8262fcce8..69c7c867be5 100644 --- a/zkevm-circuits/src/state_circuit/dev.rs +++ b/zkevm-circuits/src/state_circuit/dev.rs @@ -1,3 +1,4 @@ +use super::test::MaxNBitTable; pub use super::StateCircuit; use crate::{ @@ -26,6 +27,9 @@ where let rw_table = RwTable::construct(meta); let mpt_table = MptTable::construct(meta); let challenges = Challenges::construct(meta); + let u8_table = MaxNBitTable::construct(meta); + let u10_table = MaxNBitTable::construct(meta); + let u16_table = MaxNBitTable::construct(meta); let config = { let challenges = challenges.exprs(meta); @@ -34,6 +38,9 @@ where StateCircuitConfigArgs { rw_table, mpt_table, + u8_table, + u10_table, + u16_table, challenges, }, ) diff --git a/zkevm-circuits/src/state_circuit/lookups.rs b/zkevm-circuits/src/state_circuit/lookups.rs index 5bea09914d6..4eadd16f39b 100644 --- a/zkevm-circuits/src/state_circuit/lookups.rs +++ b/zkevm-circuits/src/state_circuit/lookups.rs @@ -8,6 +8,8 @@ use halo2_proofs::{ use std::marker::PhantomData; use strum::IntoEnumIterator; +use super::test::{LookupTable, MaxNBitTable}; + #[derive(Clone, Copy, Debug)] pub struct Config { // Can these be TableColumn's? @@ -86,16 +88,24 @@ impl Chip { } } - pub fn configure(meta: &mut ConstraintSystem) -> Config { + pub fn configure( + meta: &mut ConstraintSystem, + u8_table: MaxNBitTable<8>, + u10_table: MaxNBitTable<10>, + u16_table: MaxNBitTable<16>, + ) -> Config { + debug_assert_eq!(u8_table.columns().len(), 1); + debug_assert_eq!(u10_table.columns().len(), 1); + debug_assert_eq!(u16_table.columns().len(), 1); let config = Config { - u8: meta.fixed_column(), - u10: meta.fixed_column(), - u16: meta.fixed_column(), + u8: u8_table.columns()[0], + u10: u10_table.columns()[0], + u16: u16_table.columns()[0], call_context_field_tag: meta.fixed_column(), }; - meta.annotate_lookup_any_column(config.u8, || "LOOKUP_u8"); - meta.annotate_lookup_any_column(config.u10, || "LOOKUP_u10"); - meta.annotate_lookup_any_column(config.u16, || "LOOKUP_u16"); + u8_table.annotate_columns(meta); + u10_table.annotate_columns(meta); + u16_table.annotate_columns(meta); meta.annotate_lookup_any_column(config.call_context_field_tag, || { "LOOKUP_call_context_field_tag" }); @@ -103,26 +113,6 @@ impl Chip { } pub fn load(&self, layouter: &mut impl Layouter) -> Result<(), Error> { - for (column, exponent) in [ - (self.config.u8, 8), - (self.config.u10, 10), - (self.config.u16, 16), - ] { - layouter.assign_region( - || format!("assign u{} fixed column", exponent), - |mut region| { - for i in 0..(1 << exponent) { - region.assign_fixed( - || format!("assign {} in u{} fixed column", i, exponent), - column, - i, - || Value::known(F::from(i as u64)), - )?; - } - Ok(()) - }, - )?; - } layouter.assign_region( || "assign call_context_field_tags fixed column", |mut region| { diff --git a/zkevm-circuits/src/super_circuit.rs b/zkevm-circuits/src/super_circuit.rs index f203e5d3cc8..0b4e372ebbb 100644 --- a/zkevm-circuits/src/super_circuit.rs +++ b/zkevm-circuits/src/super_circuit.rs @@ -64,7 +64,8 @@ use crate::{ pi_circuit::{PiCircuit, PiCircuitConfig, PiCircuitConfigArgs}, state_circuit::{StateCircuit, StateCircuitConfig, StateCircuitConfigArgs}, table::{ - BlockTable, BytecodeTable, CopyTable, ExpTable, KeccakTable, MptTable, RwTable, TxTable, + BlockTable, BytecodeTable, CopyTable, ExpTable, KeccakTable, MaxNBitTable, MptTable, + RwTable, TxTable, }, tx_circuit::{TxCircuit, TxCircuitConfig, TxCircuitConfigArgs}, util::{log2_ceil, Challenges, SubCircuit, SubCircuitConfig}, @@ -87,6 +88,9 @@ use std::array; pub struct SuperCircuitConfig { block_table: BlockTable, mpt_table: MptTable, + u8_table: MaxNBitTable<8>, + u10_table: MaxNBitTable<10>, + u16_table: MaxNBitTable<16>, evm_circuit: EvmCircuitConfig, state_circuit: StateCircuitConfig, tx_circuit: TxCircuitConfig, @@ -128,6 +132,9 @@ impl SubCircuitConfig for SuperCircuitConfig { let copy_table = CopyTable::construct(meta, q_copy_table); let exp_table = ExpTable::construct(meta); let keccak_table = KeccakTable::construct(meta); + let u8_table = MaxNBitTable::construct(meta); + let u10_table = MaxNBitTable::construct(meta); + let u16_table = MaxNBitTable::construct(meta); // Use a mock randomness instead of the randomness derived from the challange // (either from mock or real prover) to help debugging assignments. @@ -190,6 +197,9 @@ impl SubCircuitConfig for SuperCircuitConfig { StateCircuitConfigArgs { rw_table, mpt_table, + u8_table, + u10_table, + u16_table, challenges: challenges.clone(), }, ); @@ -205,12 +215,17 @@ impl SubCircuitConfig for SuperCircuitConfig { copy_table, keccak_table, exp_table, + u8_table, + u16_table, }, ); Self { block_table, mpt_table, + u8_table, + u10_table, + u16_table, evm_circuit, state_circuit, copy_circuit, @@ -414,6 +429,10 @@ impl LookupTable for ExpTable { ] } } + +// fixed table to serve max unsigned N bits range lookup +pub struct MaxNBitTable { + col: Column, +} + +impl MaxNBitTable { + /// Construct the Exponentiation table. + pub fn construct(meta: &mut ConstraintSystem) -> Self { + Self { + col: meta.fixed_column(), + } + } + + pub fn load(&self, layouter: &mut impl Layouter) -> Result<(), Error> { + layouter.assign_region( + || format!("assign u{} fixed column", 8), + |mut region| { + for i in 0..(1 << N_BITS) { + region.assign_fixed( + || format!("assign {} in u{} fixed column", i, N_BITS), + self.col, + i, + || Value::known(F::from(i as u64)), + )?; + } + Ok(()) + }, + )?; + Ok(()) + } +} + +impl LookupTable for MaxNBitTable { + fn columns(&self) -> Vec> { + vec![self.col.into()] + } + + fn annotations(&self) -> Vec { + vec![String::from(format!("u{}_col", N_BITS))] + } + + fn table_exprs(&self, meta: &mut VirtualCells) -> Vec> { + vec![meta.query_fixed(self.col, Rotation::cur())] + } +}