diff --git a/zkevm-circuits/src/bin/stats/main.rs b/zkevm-circuits/src/bin/stats/main.rs index 30c8fc9a27d..214340676f2 100644 --- a/zkevm-circuits/src/bin/stats/main.rs +++ b/zkevm-circuits/src/bin/stats/main.rs @@ -10,7 +10,10 @@ use itertools::Itertools; use mock::MOCK_ACCOUNTS; use std::env; use zkevm_circuits::evm_circuit::{ - param::{LOOKUP_CONFIG, N_BYTE_LOOKUPS, N_COPY_COLUMNS, N_PHASE1_COLUMNS, N_PHASE2_COLUMNS}, + param::{ + LOOKUP_CONFIG, N_COPY_COLUMNS, N_PHASE1_COLUMNS, N_PHASE2_COLUMNS, N_U16_LOOKUPS, + N_U8_LOOKUPS, + }, step::ExecutionState, EvmCircuit, }; @@ -163,8 +166,10 @@ fn get_exec_steps_occupancy() { N_PHASE2_COLUMNS, storage_perm, N_COPY_COLUMNS, - byte_lookup, - N_BYTE_LOOKUPS, + u8_lookup, + N_U8_LOOKUPS, + u16_lookup, + N_U16_LOOKUPS, fixed_table, LOOKUP_CONFIG[0].1, tx_table, diff --git a/zkevm-circuits/src/evm_circuit.rs b/zkevm-circuits/src/evm_circuit.rs index 09c968cad7c..33da7358791 100644 --- a/zkevm-circuits/src/evm_circuit.rs +++ b/zkevm-circuits/src/evm_circuit.rs @@ -23,6 +23,7 @@ use crate::{ evm_circuit::param::{MAX_STEP_HEIGHT, STEP_STATE_HEIGHT}, table::{ BlockTable, BytecodeTable, CopyTable, ExpTable, KeccakTable, LookupTable, RwTable, TxTable, + UXTable, }, util::{Challenges, SubCircuit, SubCircuitConfig}, }; @@ -38,7 +39,8 @@ use witness::Block; #[derive(Clone, Debug)] pub struct EvmCircuitConfig { fixed_table: [Column; 4], - byte_table: [Column; 1], + u8_table: UXTable<8>, + u16_table: UXTable<16>, pub execution: Box>, // External tables tx_table: TxTable, @@ -68,6 +70,10 @@ pub struct EvmCircuitConfigArgs { pub keccak_table: KeccakTable, /// ExpTable pub exp_table: ExpTable, + /// U8Table + pub u8_table: UXTable<8>, + /// U16Table + pub u16_table: UXTable<16>, } impl SubCircuitConfig for EvmCircuitConfig { @@ -85,15 +91,17 @@ 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 byte_table = [(); 1].map(|_| meta.fixed_column()); let execution = Box::new(ExecutionConfig::configure( meta, challenges, &fixed_table, - &byte_table, + &u8_table, + &u16_table, &tx_table, &rw_table, &bytecode_table, @@ -103,7 +111,8 @@ impl SubCircuitConfig for EvmCircuitConfig { &exp_table, )); - meta.annotate_lookup_any_column(byte_table[0], || "byte_range"); + u8_table.annotate_columns(meta); + u16_table.annotate_columns(meta); fixed_table.iter().enumerate().for_each(|(idx, &col)| { meta.annotate_lookup_any_column(col, || format!("fix_table_{}", idx)) }); @@ -114,10 +123,13 @@ 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, - byte_table, + u8_table, + u16_table, execution, tx_table, rw_table, @@ -153,25 +165,6 @@ impl EvmCircuitConfig { }, ) } - - /// Load byte table - pub fn load_byte_table(&self, layouter: &mut impl Layouter) -> Result<(), Error> { - layouter.assign_region( - || "byte table", - |mut region| { - for offset in 0..256 { - region.assign_fixed( - || "", - self.byte_table[0], - offset, - || Value::known(F::from(offset as u64)), - )?; - } - - Ok(()) - }, - ) - } } /// Tx Circuit for verifying transaction signatures @@ -270,7 +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_byte_table(layouter)?; config.execution.assign_block(layouter, block, challenges) } } @@ -375,6 +367,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 = UXTable::construct(meta); + let u16_table = UXTable::construct(meta); let challenges = Challenges::construct(meta); let challenges_expr = challenges.exprs(meta); @@ -390,6 +384,8 @@ impl Circuit for EvmCircuit { copy_table, keccak_table, exp_table, + u8_table, + u16_table, }, ), challenges, @@ -428,6 +424,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 1ce419f6359..b48f357a6a8 100644 --- a/zkevm-circuits/src/evm_circuit/execution.rs +++ b/zkevm-circuits/src/evm_circuit/execution.rs @@ -1,8 +1,8 @@ use super::{ param::{ BLOCK_TABLE_LOOKUPS, BYTECODE_TABLE_LOOKUPS, COPY_TABLE_LOOKUPS, EXP_TABLE_LOOKUPS, - FIXED_TABLE_LOOKUPS, KECCAK_TABLE_LOOKUPS, N_BYTE_LOOKUPS, N_COPY_COLUMNS, - N_PHASE1_COLUMNS, RW_TABLE_LOOKUPS, TX_TABLE_LOOKUPS, + FIXED_TABLE_LOOKUPS, KECCAK_TABLE_LOOKUPS, N_COPY_COLUMNS, N_PHASE1_COLUMNS, N_U16_LOOKUPS, + N_U8_LOOKUPS, RW_TABLE_LOOKUPS, TX_TABLE_LOOKUPS, }, step::HasExecutionState, util::{instrumentation::Instrument, CachedRegion, CellManager, StoredExpression}, @@ -319,7 +319,8 @@ impl ExecutionConfig { meta: &mut ConstraintSystem, challenges: Challenges>, fixed_table: &dyn LookupTable, - byte_table: &dyn LookupTable, + u8_table: &dyn LookupTable, + u16_table: &dyn LookupTable, tx_table: &dyn LookupTable, rw_table: &dyn LookupTable, bytecode_table: &dyn LookupTable, @@ -579,7 +580,8 @@ impl ExecutionConfig { Self::configure_lookup( meta, fixed_table, - byte_table, + u8_table, + u16_table, tx_table, rw_table, bytecode_table, @@ -795,7 +797,8 @@ impl ExecutionConfig { fn configure_lookup( meta: &mut ConstraintSystem, fixed_table: &dyn LookupTable, - byte_table: &dyn LookupTable, + u8_table: &dyn LookupTable, + u16_table: &dyn LookupTable, tx_table: &dyn LookupTable, rw_table: &dyn LookupTable, bytecode_table: &dyn LookupTable, @@ -829,10 +832,24 @@ impl ExecutionConfig { } } for column in cell_manager.columns().iter() { - if let CellType::LookupByte = column.cell_type { - meta.lookup_any("Byte lookup", |meta| { - let byte_table_expression = byte_table.table_exprs(meta)[0].clone(); - vec![(column.expr(), byte_table_expression)] + if let CellType::LookupU8 = column.cell_type { + meta.lookup_any("u8 lookup", |meta| { + vec![column.expr()] + .into_iter() + .zip(u8_table.table_exprs(meta).into_iter()) + .map(|(expr, table)| (expr, table)) + .collect() + }); + } + } + for column in cell_manager.columns().iter() { + if let CellType::LookupU16 = column.cell_type { + meta.lookup_any("u16 lookup", |meta| { + vec![column.expr()] + .into_iter() + .zip(u16_table.table_exprs(meta).into_iter()) + .map(|(expr, table)| (expr, table)) + .collect() }); } } @@ -1034,7 +1051,8 @@ impl ExecutionConfig { ("EVM_lookup_exp", EXP_TABLE_LOOKUPS), ("EVM_adv_phase2", N_PHASE2_COLUMNS), ("EVM_copy", N_COPY_COLUMNS), - ("EVM_lookup_byte", N_BYTE_LOOKUPS), + ("EVM_lookup_u8", N_U8_LOOKUPS), + ("EVM_lookup_u16", N_U16_LOOKUPS), ("EVM_adv_phase1", N_PHASE1_COLUMNS), ]; let mut group_index = 0; diff --git a/zkevm-circuits/src/evm_circuit/param.rs b/zkevm-circuits/src/evm_circuit/param.rs index ee9f10fbb19..3b45b17fb68 100644 --- a/zkevm-circuits/src/evm_circuit/param.rs +++ b/zkevm-circuits/src/evm_circuit/param.rs @@ -20,12 +20,14 @@ pub const N_PHASE2_COLUMNS: usize = 4; /// Number of Advice Phase1 columns in the EVM circuit pub const N_PHASE1_COLUMNS: usize = - STEP_WIDTH - EVM_LOOKUP_COLS - N_PHASE2_COLUMNS - N_COPY_COLUMNS - N_BYTE_LOOKUPS; + STEP_WIDTH - EVM_LOOKUP_COLS - N_PHASE2_COLUMNS - N_COPY_COLUMNS - N_U8_LOOKUPS - N_U16_LOOKUPS; // Number of copy columns pub const N_COPY_COLUMNS: usize = 2; -pub const N_BYTE_LOOKUPS: usize = 24; +pub const N_U8_LOOKUPS: usize = 12; + +pub const N_U16_LOOKUPS: usize = 6; /// Amount of lookup columns in the EVM circuit dedicated to lookups. pub(crate) const EVM_LOOKUP_COLS: usize = FIXED_TABLE_LOOKUPS diff --git a/zkevm-circuits/src/evm_circuit/util.rs b/zkevm-circuits/src/evm_circuit/util.rs index 672c7960877..099924254ef 100644 --- a/zkevm-circuits/src/evm_circuit/util.rs +++ b/zkevm-circuits/src/evm_circuit/util.rs @@ -6,7 +6,7 @@ pub use crate::util::{ use crate::{ evm_circuit::{ param::{ - LOOKUP_CONFIG, N_BYTES_MEMORY_ADDRESS, N_BYTE_LOOKUPS, N_COPY_COLUMNS, N_PHASE2_COLUMNS, + LOOKUP_CONFIG, N_BYTES_MEMORY_ADDRESS, N_COPY_COLUMNS, N_PHASE2_COLUMNS, N_U8_LOOKUPS, }, table::Table, }, @@ -34,7 +34,7 @@ pub(crate) mod memory_gadget; pub use gadgets::util::{and, not, or, select, sum}; -use super::param::{N_BYTES_ACCOUNT_ADDRESS, N_BYTES_U64}; +use super::param::{N_BYTES_ACCOUNT_ADDRESS, N_BYTES_U64, N_U16_LOOKUPS}; #[derive(Clone, Debug)] pub struct Cell { @@ -294,7 +294,9 @@ pub(crate) enum CellType { StoragePhase1, StoragePhase2, StoragePermutation, - LookupByte, + // TODO combine LookupU8, LookupU16 with Lookup(Table::U8 | Table::U16) + LookupU8, + LookupU16, Lookup(Table), } @@ -397,8 +399,15 @@ impl CellManager { } // Mark columns used for byte lookup - for _ in 0..N_BYTE_LOOKUPS { - columns[column_idx].cell_type = CellType::LookupByte; + for _ in 0..N_U8_LOOKUPS { + columns[column_idx].cell_type = CellType::LookupU8; + assert_eq!(advices[column_idx].column_type().phase(), 0); + column_idx += 1; + } + + // Mark columns used for byte lookup + for _ in 0..N_U16_LOOKUPS { + columns[column_idx].cell_type = CellType::LookupU16; assert_eq!(advices[column_idx].column_type().phase(), 0); column_idx += 1; } diff --git a/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs b/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs index 65ce6106ca7..62dba7bbe05 100644 --- a/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs +++ b/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs @@ -417,7 +417,7 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { } pub(crate) fn query_byte(&mut self) -> Cell { - self.query_cell_with_type(CellType::LookupByte) + self.query_cell_with_type(CellType::LookupU8) } // default query_word is 2 limbs. Each limb is not guaranteed to be 128 bits. @@ -448,7 +448,7 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { } /// query_word4_unchecked get word with 4 limbs. Each limb is not guaranteed to be 64 bits. - pub fn query_word4_unchecked(&mut self) -> Word4> { + pub fn query_word4_unchecked(&mut self) -> Word4> { Word4::new( self.query_cells(CellType::StoragePhase1, N) .try_into() @@ -457,13 +457,8 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { } // each limb is 16 bits, and any conversion to smaller limbs inherits the type check. - // TODO implement 16bits range check pub(crate) fn query_word16(&mut self) -> Word16> { - Word16::new( - self.query_cells(CellType::StoragePhase1, N) - .try_into() - .unwrap(), - ) + Word16::new(self.query_u16()) } // query_word32 each limb is 8 bits, and any conversion to smaller limbs inherits the type @@ -489,11 +484,19 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { } pub(crate) fn query_bytes(&mut self) -> [Cell; N] { - self.query_bytes_dyn(N).try_into().unwrap() + self.query_u8_dyn(N).try_into().unwrap() + } + + pub(crate) fn query_u8_dyn(&mut self, count: usize) -> Vec> { + self.query_cells(CellType::LookupU8, count) + } + + pub(crate) fn query_u16(&mut self) -> [Cell; N] { + self.query_u16_dyn(N).try_into().unwrap() } - pub(crate) fn query_bytes_dyn(&mut self, count: usize) -> Vec> { - self.query_cells(CellType::LookupByte, count) + pub(crate) fn query_u16_dyn(&mut self, count: usize) -> Vec> { + self.query_cells(CellType::LookupU16, count) } pub(crate) fn query_cell(&mut self) -> Cell { diff --git a/zkevm-circuits/src/evm_circuit/util/instrumentation.rs b/zkevm-circuits/src/evm_circuit/util/instrumentation.rs index eef04dbace2..2ff5bc80023 100644 --- a/zkevm-circuits/src/evm_circuit/util/instrumentation.rs +++ b/zkevm-circuits/src/evm_circuit/util/instrumentation.rs @@ -73,8 +73,11 @@ impl Instrument { CellType::StoragePermutation => { report.storage_perm = data_entry; } - CellType::LookupByte => { - report.byte_lookup = data_entry; + CellType::LookupU8 => { + report.u8_lookup = data_entry; + } + CellType::LookupU16 => { + report.u16_lookup = data_entry; } CellType::Lookup(Table::Fixed) => { report.fixed_table = data_entry; @@ -116,6 +119,8 @@ pub struct ExecStateReport { pub storage_1: StateReportRow, pub storage_2: StateReportRow, pub storage_perm: StateReportRow, + pub u8_lookup: StateReportRow, + pub u16_lookup: StateReportRow, pub byte_lookup: StateReportRow, pub fixed_table: StateReportRow, pub tx_table: StateReportRow, diff --git a/zkevm-circuits/src/state_circuit.rs b/zkevm-circuits/src/state_circuit.rs index dc387a25b79..a0f84a85465 100644 --- a/zkevm-circuits/src/state_circuit.rs +++ b/zkevm-circuits/src/state_circuit.rs @@ -18,7 +18,7 @@ use self::{ lexicographic_ordering::LimbIndex, }; use crate::{ - table::{AccountFieldTag, LookupTable, MPTProofType, MptTable, RwTable}, + table::{AccountFieldTag, LookupTable, MPTProofType, MptTable, RwTable, UXTable}, util::{word, Challenges, Expr, SubCircuit, SubCircuitConfig}, witness::{self, MptUpdates, Rw, RwMap}, }; @@ -78,6 +78,12 @@ pub struct StateCircuitConfigArgs { pub rw_table: RwTable, /// MptTable pub mpt_table: MptTable, + /// U8Table + pub u8_table: UXTable<8>, + /// U10Table + pub u10_table: UXTable<10>, + /// U16Table + pub u16_table: UXTable<16>, /// Challenges pub challenges: Challenges>, } @@ -91,11 +97,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 rw_counter = MpiChip::configure(meta, selector, [rw_table.rw_counter], lookups); let tag = BinaryNumberChip::configure(meta, selector, Some(rw_table.tag)); diff --git a/zkevm-circuits/src/state_circuit/dev.rs b/zkevm-circuits/src/state_circuit/dev.rs index b56cfece0f3..382c5c79eb9 100644 --- a/zkevm-circuits/src/state_circuit/dev.rs +++ b/zkevm-circuits/src/state_circuit/dev.rs @@ -1,3 +1,4 @@ +use super::test::UXTable; pub use super::StateCircuit; use crate::{ @@ -27,6 +28,9 @@ where let rw_table = RwTable::construct(meta); let mpt_table = MptTable::construct(meta); let challenges = Challenges::construct(meta); + let u8_table = UXTable::construct(meta); + let u10_table = UXTable::construct(meta); + let u16_table = UXTable::construct(meta); let config = { let challenges = challenges.exprs(meta); @@ -35,6 +39,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..ebf0a832d6f 100644 --- a/zkevm-circuits/src/state_circuit/lookups.rs +++ b/zkevm-circuits/src/state_circuit/lookups.rs @@ -5,16 +5,19 @@ use halo2_proofs::{ plonk::{Column, ConstraintSystem, Error, Expression, Fixed, VirtualCells}, poly::Rotation, }; +use itertools::Itertools; use std::marker::PhantomData; use strum::IntoEnumIterator; +use super::test::{LookupTable, UXTable}; + #[derive(Clone, Copy, Debug)] pub struct Config { // Can these be TableColumn's? // https://github.com/zcash/halo2/blob/642efc1536d3ea2566b04814bd60a00c4745ae22/halo2_proofs/src/plonk/circuit.rs#L266 - u8: Column, - u10: Column, - u16: Column, + u8_table: UXTable<8>, + u10_table: UXTable<10>, + u16_table: UXTable<16>, pub call_context_field_tag: Column, } @@ -27,7 +30,11 @@ impl Config { ) { meta.lookup_any(msg, |meta| { let exp = exp_fn(meta); - vec![(exp, meta.query_fixed(self.u8, Rotation::cur()))] + vec![exp] + .into_iter() + .zip_eq(self.u8_table.table_exprs(meta)) + .map(|(exp, table_expr)| (exp, table_expr)) + .collect() }); } pub fn range_check_u10( @@ -38,7 +45,11 @@ impl Config { ) { meta.lookup_any(msg, |meta| { let exp = exp_fn(meta); - vec![(exp, meta.query_fixed(self.u10, Rotation::cur()))] + vec![exp] + .into_iter() + .zip_eq(self.u10_table.table_exprs(meta)) + .map(|(exp, table_expr)| (exp, table_expr)) + .collect() }); } pub fn range_check_u16( @@ -49,7 +60,11 @@ impl Config { ) { meta.lookup_any(msg, |meta| { let exp = exp_fn(meta); - vec![(exp, meta.query_fixed(self.u16, Rotation::cur()))] + vec![exp] + .into_iter() + .zip_eq(self.u16_table.table_exprs(meta)) + .map(|(exp, table_expr)| (exp, table_expr)) + .collect() }); } } @@ -65,9 +80,9 @@ pub struct Queries { impl Queries { pub fn new(meta: &mut VirtualCells<'_, F>, c: Config) -> Self { Self { - u8: meta.query_fixed(c.u8, Rotation::cur()), - u10: meta.query_fixed(c.u10, Rotation::cur()), - u16: meta.query_fixed(c.u16, Rotation::cur()), + u8: c.u8_table.table_exprs(meta)[0].clone(), + u10: c.u10_table.table_exprs(meta)[0].clone(), + u16: c.u16_table.table_exprs(meta)[0].clone(), call_context_field_tag: meta.query_fixed(c.call_context_field_tag, Rotation::cur()), } } @@ -86,16 +101,21 @@ impl Chip { } } - pub fn configure(meta: &mut ConstraintSystem) -> Config { + pub fn configure( + meta: &mut ConstraintSystem, + u8_table: UXTable<8>, + u10_table: UXTable<10>, + u16_table: UXTable<16>, + ) -> Config { let config = Config { - u8: meta.fixed_column(), - u10: meta.fixed_column(), - u16: meta.fixed_column(), + u8_table, + u10_table, + u16_table, 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 +123,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 6db791c2173..cd9bb48bf62 100644 --- a/zkevm-circuits/src/super_circuit.rs +++ b/zkevm-circuits/src/super_circuit.rs @@ -65,6 +65,7 @@ use crate::{ state_circuit::{StateCircuit, StateCircuitConfig, StateCircuitConfigArgs}, table::{ BlockTable, BytecodeTable, CopyTable, ExpTable, KeccakTable, MptTable, RwTable, TxTable, + UXTable, }, 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: UXTable<8>, + u10_table: UXTable<10>, + u16_table: UXTable<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 = UXTable::construct(meta); + let u10_table = UXTable::construct(meta); + let u16_table = UXTable::construct(meta); // Use a mock randomness instead of the randomness derived from the challange // (either from mock or real prover) to help debugging assignments. @@ -189,6 +196,9 @@ impl SubCircuitConfig for SuperCircuitConfig { StateCircuitConfigArgs { rw_table, mpt_table, + u8_table, + u10_table, + u16_table, challenges: challenges.clone(), }, ); @@ -204,12 +214,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, @@ -422,6 +437,10 @@ impl Circuit for SuperCircuit { .mpt_table .load(&mut layouter, &MptUpdates::mock_from(rws))?; + config.u8_table.load(&mut layouter)?; + config.u10_table.load(&mut layouter)?; + config.u16_table.load(&mut layouter)?; + self.synthesize_sub(&config, &challenges, &mut layouter) } } diff --git a/zkevm-circuits/src/table.rs b/zkevm-circuits/src/table.rs index fa8f5ab10a9..4953765306d 100644 --- a/zkevm-circuits/src/table.rs +++ b/zkevm-circuits/src/table.rs @@ -41,12 +41,15 @@ pub(crate) mod mpt_table; pub(crate) mod rw_table; /// tx table pub(crate) mod tx_table; +/// ux table +pub(crate) mod ux_table; pub(crate) use block_table::{BlockContextFieldTag, BlockTable}; pub(crate) use bytecode_table::{BytecodeFieldTag, BytecodeTable}; pub(crate) use copy_table::CopyTable; pub(crate) use exp_table::ExpTable; pub(crate) use keccak_table::KeccakTable; +pub(crate) use ux_table::UXTable; pub(crate) use mpt_table::{MPTProofType, MptTable}; pub(crate) use rw_table::RwTable; diff --git a/zkevm-circuits/src/table/ux_table.rs b/zkevm-circuits/src/table/ux_table.rs new file mode 100644 index 00000000000..74427fb2186 --- /dev/null +++ b/zkevm-circuits/src/table/ux_table.rs @@ -0,0 +1,49 @@ +use super::*; + +/// Lookup table for max n bits range check +#[derive(Clone, Copy, Debug)] +pub struct UXTable { + col: Column, +} + +impl UXTable { + /// Construct the Exponentiation table. + pub fn construct(meta: &mut ConstraintSystem) -> Self { + Self { + col: meta.fixed_column(), + } + } + + /// Load the `UXTable` for range check + 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 UXTable { + fn columns(&self) -> Vec> { + vec![self.col.into()] + } + + fn annotations(&self) -> Vec { + vec![format!("u{}_col", N_BITS)] + } + + fn table_exprs(&self, meta: &mut VirtualCells) -> Vec> { + vec![meta.query_fixed(self.col, Rotation::cur())] + } +}