diff --git a/zkevm-circuits/src/evm_circuit.rs b/zkevm-circuits/src/evm_circuit.rs index e1f19121ed0..10ca0485e7c 100644 --- a/zkevm-circuits/src/evm_circuit.rs +++ b/zkevm-circuits/src/evm_circuit.rs @@ -37,7 +37,8 @@ use witness::Block; #[derive(Clone, Debug)] pub struct EvmCircuitConfig { fixed_table: [Column; 4], - byte_table: [Column; 1], + u8_table: [Column; 1], // byte table + u16_table: [Column; 1], // 2 bytes table. pub(crate) execution: Box>, // External tables tx_table: TxTable, @@ -88,12 +89,14 @@ impl SubCircuitConfig for EvmCircuitConfig { }: Self::ConfigArgs, ) -> Self { let fixed_table = [(); 4].map(|_| meta.fixed_column()); - let byte_table = [(); 1].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, &fixed_table, - &byte_table, + &u8_table, + &u16_table, &tx_table, &rw_table, &bytecode_table, @@ -103,7 +106,8 @@ impl SubCircuitConfig for EvmCircuitConfig { &exp_table, )); - meta.annotate_lookup_any_column(byte_table[0], || "byte_range"); + meta.annotate_lookup_any_column(u8_table[0], || "u8_range"); + meta.annotate_lookup_any_column(u16_table[0], || "u16_range"); fixed_table.iter().enumerate().for_each(|(idx, &col)| { meta.annotate_lookup_any_column(col, || format!("fix_table_{}", idx)) }); @@ -117,7 +121,8 @@ impl SubCircuitConfig for EvmCircuitConfig { Self { fixed_table, - byte_table, + u8_table, + u16_table, execution, tx_table, rw_table, @@ -154,15 +159,34 @@ impl EvmCircuitConfig { ) } - /// Load byte table - pub fn load_byte_table(&self, layouter: &mut impl Layouter) -> Result<(), Error> { + /// Load u8 table + pub fn load_u8_table(&self, layouter: &mut impl Layouter) -> Result<(), Error> { layouter.assign_region( - || "byte table", + || "u8 table", |mut region| { - for offset in 0..256 { + for offset in 0..(1 << 8) { region.assign_fixed( || "", - self.byte_table[0], + 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)), )?; @@ -270,7 +294,8 @@ 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.load_u8_table(layouter)?; + config.load_u16_table(layouter)?; config.execution.assign_block(layouter, block, challenges) } } @@ -439,7 +464,8 @@ mod evm_circuit_stats { use crate::{ evm_circuit::{ param::{ - LOOKUP_CONFIG, N_BYTE_LOOKUPS, N_COPY_COLUMNS, N_PHASE1_COLUMNS, N_PHASE2_COLUMNS, + LOOKUP_CONFIG, N_COPY_COLUMNS, N_PHASE1_COLUMNS, N_PHASE2_COLUMNS, N_U16_LOOKUPS, + N_U8_LOOKUPS, }, step::ExecutionState, EvmCircuit, @@ -594,8 +620,10 @@ mod evm_circuit_stats { 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/execution.rs b/zkevm-circuits/src/evm_circuit/execution.rs index 630200b5ece..d3d3b6fca03 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, }, 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, @@ -581,7 +582,8 @@ impl ExecutionConfig { Self::configure_lookup( meta, fixed_table, - byte_table, + u8_table, + u16_table, tx_table, rw_table, bytecode_table, @@ -797,7 +799,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, @@ -831,10 +834,18 @@ 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| { + let u8_table_expression = u8_table.table_exprs(meta)[0].clone(); + vec![(column.expr(), u8_table_expression)] + }); + } + } + for column in cell_manager.columns().iter() { + if let CellType::LookupU16 = column.cell_type { + meta.lookup_any("u16 lookup", |meta| { + let u16_table_expression = u16_table.table_exprs(meta)[0].clone(); + vec![(column.expr(), u16_table_expression)] }); } } @@ -1036,7 +1047,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 e687f01d6a2..765bec4ff71 100644 --- a/zkevm-circuits/src/evm_circuit/param.rs +++ b/zkevm-circuits/src/evm_circuit/param.rs @@ -20,12 +20,14 @@ pub(crate) const N_PHASE2_COLUMNS: usize = 4; /// Number of Advice Phase1 columns in the EVM circuit pub(crate) 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(crate) const N_COPY_COLUMNS: usize = 2; -pub(crate) const N_BYTE_LOOKUPS: usize = 24; +pub(crate) const N_U8_LOOKUPS: usize = 12; + +pub(crate) 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 0a02df71ca1..b3dbb218fa9 100644 --- a/zkevm-circuits/src/evm_circuit/util.rs +++ b/zkevm-circuits/src/evm_circuit/util.rs @@ -1,7 +1,7 @@ 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(crate) struct Cell { @@ -276,7 +276,8 @@ pub(crate) enum CellType { StoragePhase1, StoragePhase2, StoragePermutation, - LookupByte, + LookupU8, + LookupU16, Lookup(Table), } @@ -379,8 +380,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 8b20696b5f7..17863665663 100644 --- a/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs +++ b/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs @@ -416,7 +416,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) } // TODO remove me @@ -452,7 +452,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() @@ -461,13 +461,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_dyn(N)) } // query_word32 each limb is 8 bits, and any conversion to smaller limbs inherits the type @@ -481,23 +476,27 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { } pub(crate) fn query_u64(&mut self) -> U64Cell { - U64Cell::new(self.query_bytes(), 256u64.expr()) + U64Cell::new(self.query_bytes(), (1 << 8).expr()) } pub(crate) fn query_account_address(&mut self) -> AccountAddress { - AccountAddress::::new(self.query_bytes(), 256u64.expr()) + AccountAddress::::new(self.query_bytes(), (1 << 8).expr()) } pub(crate) fn query_memory_address(&mut self) -> MemoryAddress { - MemoryAddress::::new(self.query_bytes(), 256u64.expr()) + MemoryAddress::::new(self.query_bytes(), (1 << 8).expr()) } 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_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 7f03fe68643..28ad3202270 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,7 +119,8 @@ pub(crate) struct ExecStateReport { pub(crate) storage_1: StateReportRow, pub(crate) storage_2: StateReportRow, pub(crate) storage_perm: StateReportRow, - pub(crate) byte_lookup: StateReportRow, + pub(crate) u8_lookup: StateReportRow, + pub(crate) u16_lookup: StateReportRow, pub(crate) fixed_table: StateReportRow, pub(crate) tx_table: StateReportRow, pub(crate) rw_table: StateReportRow,