diff --git a/Cargo.toml b/Cargo.toml index 787835aeea..ac0189884b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,6 @@ members = [ "prover" ] - [patch.crates-io] # This fork makes bitvec 0.20.x work with funty 1.1 and funty 1.2. Without # this fork, bitvec 0.20.x is incompatible with funty 1.2, which we depend on, diff --git a/Makefile b/Makefile index cddba15f7d..ea755b7aaa 100644 --- a/Makefile +++ b/Makefile @@ -22,7 +22,7 @@ test_benches: ## Compiles the benchmarks test-all: fmt doc clippy test_benches test ## Run all the CI checks locally (in your actual toolchain) -evm_bench: ## Run Evm Circuit benchmarks +evm_bench: ## Run Evm Circuit benchmarks @cargo test --profile bench bench_evm_circuit_prover -p circuit-benchmarks --features benches -- --nocapture state_bench: ## Run State Circuit benchmarks diff --git a/circuit-benchmarks/src/evm_circuit.rs b/circuit-benchmarks/src/evm_circuit.rs index ee34dacc06..a7c648ddda 100644 --- a/circuit-benchmarks/src/evm_circuit.rs +++ b/circuit-benchmarks/src/evm_circuit.rs @@ -32,10 +32,10 @@ impl Circuit for TestCircuit { EvmCircuit::configure( meta, power_of_randomness, - tx_table, - rw_table, - bytecode_table, - block_table, + &tx_table, + &rw_table, + &bytecode_table, + &block_table, ) } diff --git a/zkevm-circuits/src/evm_circuit.rs b/zkevm-circuits/src/evm_circuit.rs index 3fdb2d219b..62e47ec712 100644 --- a/zkevm-circuits/src/evm_circuit.rs +++ b/zkevm-circuits/src/evm_circuit.rs @@ -17,37 +17,32 @@ use itertools::Itertools; use table::{FixedTableTag, LookupTable}; use witness::Block; -use self::param::STEP_HEIGHT; - /// EvmCircuit implements verification of execution trace of a block. #[derive(Clone, Debug)] pub struct EvmCircuit { fixed_table: [Column; 4], + byte_table: [Column; 1], execution: ExecutionConfig, } impl EvmCircuit { /// Configure EvmCircuit - pub fn configure( + pub fn configure( meta: &mut ConstraintSystem, power_of_randomness: [Expression; 31], - tx_table: TxTable, - rw_table: RwTable, - bytecode_table: BytecodeTable, - block_table: BlockTable, - ) -> Self - where - TxTable: LookupTable, - RwTable: LookupTable, - BytecodeTable: LookupTable, - BlockTable: LookupTable, - { + tx_table: &dyn LookupTable, + rw_table: &dyn LookupTable, + bytecode_table: &dyn LookupTable, + block_table: &dyn LookupTable, + ) -> Self { let fixed_table = [(); 4].map(|_| meta.fixed_column()); + let byte_table = [(); 1].map(|_| meta.fixed_column()); let execution = ExecutionConfig::configure( meta, power_of_randomness, - fixed_table, + &fixed_table, + &byte_table, tx_table, rw_table, bytecode_table, @@ -56,6 +51,7 @@ impl EvmCircuit { Self { fixed_table, + byte_table, execution, } } @@ -83,33 +79,64 @@ impl EvmCircuit { ) } + /// 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, + || Ok(F::from(offset as u64)), + )?; + } + + Ok(()) + }, + ) + } + /// Assign block pub fn assign_block( &self, layouter: &mut impl Layouter, block: &Block, ) -> Result<(), Error> { - self.execution.assign_block(layouter, block) + self.execution.assign_block(layouter, block, false) } /// Assign exact steps in block without padding for unit test purpose + #[cfg(any(feature = "test", test))] pub fn assign_block_exact( &self, layouter: &mut impl Layouter, block: &Block, ) -> Result<(), Error> { - self.execution.assign_block_exact(layouter, block) + self.execution.assign_block(layouter, block, true) } /// Calculate which rows are "actually" used in the circuit - pub fn get_active_rows(block: &Block) -> (Vec, Vec) { - let max_offset = block.txs.iter().map(|tx| tx.steps.len()).sum::() * STEP_HEIGHT; - // gates are only enabled at "q_step" rows - let gates_row_ids = (0..max_offset).step_by(STEP_HEIGHT).collect(); + pub fn get_active_rows(&self, block: &Block) -> (Vec, Vec) { + let max_offset = self.get_num_rows_required(block); + // some gates are enabled on all rows + let gates_row_ids = (0..max_offset).collect(); // lookups are enabled at "q_step" rows and byte lookup rows let lookup_row_ids = (0..max_offset).collect(); (gates_row_ids, lookup_row_ids) } + + pub fn get_num_rows_required(&self, block: &Block) -> usize { + // Start at 1 so we can be sure there is an unused `next` row available + let mut num_rows = 1; + for transaction in &block.txs { + for step in &transaction.steps { + num_rows += self.execution.get_step_height(step.execution_state); + } + } + num_rows + } } #[cfg(any(feature = "test", test))] @@ -117,7 +144,6 @@ pub mod test { use crate::{ evm_circuit::{ - param::STEP_HEIGHT, table::FixedTableTag, witness::{Block, BlockContext, Bytecode, RwMap, Transaction}, EvmCircuit, @@ -377,10 +403,10 @@ pub mod test { evm_circuit: EvmCircuit::configure( meta, power_of_randomness, - tx_table, - rw_table, - bytecode_table, - block_table, + &tx_table, + &rw_table, + &bytecode_table, + &block_table, ), } } @@ -393,6 +419,7 @@ pub mod test { config .evm_circuit .load_fixed_table(&mut layouter, self.fixed_table_tags.clone())?; + config.evm_circuit.load_byte_table(&mut layouter)?; config.load_txs(&mut layouter, &self.block.txs, self.block.randomness)?; config.load_rws(&mut layouter, &self.block.rws, self.block.randomness)?; config.load_bytecodes(&mut layouter, &self.block.bytecodes, self.block.randomness)?; @@ -403,12 +430,28 @@ pub mod test { } } + impl TestCircuit { + pub fn get_num_rows_required(block: &Block) -> usize { + let mut cs = ConstraintSystem::default(); + let config = TestCircuit::configure(&mut cs); + config.evm_circuit.get_num_rows_required(block) + } + + pub fn get_active_rows(block: &Block) -> (Vec, Vec) { + let mut cs = ConstraintSystem::default(); + let config = TestCircuit::configure(&mut cs); + config.evm_circuit.get_active_rows(block) + } + } + pub fn run_test_circuit( block: Block, fixed_table_tags: Vec, ) -> Result<(), Vec> { let log2_ceil = |n| u32::BITS - (n as u32).leading_zeros() - (n & (n - 1) == 0) as u32; + let num_rows_required_for_steps = TestCircuit::get_num_rows_required(&block); + let k = log2_ceil( 64 + fixed_table_tags .iter() @@ -422,20 +465,13 @@ pub mod test { .map(|bytecode| bytecode.bytes.len()) .sum::(), )); - let k = k.max(log2_ceil( - 64 + block.txs.iter().map(|tx| tx.steps.len()).sum::() * STEP_HEIGHT, - )); + let k = k.max(log2_ceil(64 + num_rows_required_for_steps)); log::debug!("evm circuit uses k = {}", k); let power_of_randomness = (1..32) - .map(|exp| { - vec![ - block.randomness.pow(&[exp, 0, 0, 0]); - block.txs.iter().map(|tx| tx.steps.len()).sum::() * STEP_HEIGHT - ] - }) + .map(|exp| vec![block.randomness.pow(&[exp, 0, 0, 0]); (1 << k) - 64]) .collect(); - let (active_gate_rows, active_lookup_rows) = EvmCircuit::get_active_rows(&block); + let (active_gate_rows, active_lookup_rows) = TestCircuit::get_active_rows(&block); let circuit = TestCircuit::::new(block, fixed_table_tags); let prover = MockProver::::run(k, &circuit, power_of_randomness).unwrap(); prover.verify_at_rows(active_gate_rows.into_iter(), active_lookup_rows.into_iter()) @@ -447,6 +483,7 @@ pub mod test { run_test_circuit( block, vec![ + FixedTableTag::Zero, FixedTableTag::Range5, FixedTableTag::Range16, FixedTableTag::Range32, diff --git a/zkevm-circuits/src/evm_circuit/execution.rs b/zkevm-circuits/src/evm_circuit/execution.rs index 19ed3b7d25..c63266a019 100644 --- a/zkevm-circuits/src/evm_circuit/execution.rs +++ b/zkevm-circuits/src/evm_circuit/execution.rs @@ -1,9 +1,13 @@ +use super::util::{CachedRegion, CellManager, StoredExpression}; use crate::{ evm_circuit::{ - param::{STEP_HEIGHT, STEP_WIDTH}, - step::{ExecutionState, Preset, Step}, - table::{FixedTableTag, Lookup, LookupTable, Table}, - util::constraint_builder::ConstraintBuilder, + param::{MAX_STEP_HEIGHT, STEP_WIDTH}, + step::{ExecutionState, Step}, + table::{LookupTable, Table}, + util::{ + constraint_builder::{BaseConstraintBuilder, ConstraintBuilder}, + rlc, CellType, + }, witness::{Block, Call, ExecStep, Transaction}, }, util::Expr, @@ -12,10 +16,10 @@ use eth_types::Field; use halo2_proofs::{ arithmetic::FieldExt, circuit::{Layouter, Region}, - plonk::{Column, ConstraintSystem, Error, Expression, Fixed, Selector}, + plonk::{Advice, Column, ConstraintSystem, Error, Expression, Selector, VirtualCells}, poly::Rotation, }; -use std::{collections::HashMap, iter}; +use std::{collections::HashMap, convert::TryInto, iter}; mod add_sub; mod begin_tx; @@ -114,7 +118,7 @@ pub(crate) trait ExecutionGadget { fn assign_exec_step( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, block: &Block, transaction: &Transaction, @@ -125,12 +129,17 @@ pub(crate) trait ExecutionGadget { #[derive(Clone, Debug)] pub(crate) struct ExecutionConfig { - q_step: Selector, + q_usable: Selector, + q_step: Column, + num_rows_until_next_step: Column, + num_rows_inv: Column, q_step_first: Selector, q_step_last: Selector, + advices: [Column; STEP_WIDTH], step: Step, - presets_map: HashMap>>, // internal state gadgets + height_map: HashMap, + stored_expressions_map: HashMap>>, begin_tx_gadget: BeginTxGadget, copy_to_memory_gadget: CopyToMemoryGadget, end_block_gadget: EndBlockGadget, @@ -181,34 +190,31 @@ pub(crate) struct ExecutionConfig { } impl ExecutionConfig { - pub(crate) fn configure( + #[allow(clippy::too_many_arguments)] + pub(crate) fn configure( meta: &mut ConstraintSystem, power_of_randomness: [Expression; 31], - fixed_table: [Column; 4], - tx_table: TxTable, - rw_table: RwTable, - bytecode_table: BytecodeTable, - block_table: BlockTable, - ) -> Self - where - TxTable: LookupTable, - RwTable: LookupTable, - BytecodeTable: LookupTable, - BlockTable: LookupTable, - { - let q_step = meta.complex_selector(); + fixed_table: &dyn LookupTable, + byte_table: &dyn LookupTable, + tx_table: &dyn LookupTable, + rw_table: &dyn LookupTable, + bytecode_table: &dyn LookupTable, + block_table: &dyn LookupTable, + ) -> Self { + let q_usable = meta.complex_selector(); + let q_step = meta.advice_column(); + let num_rows_until_next_step = meta.advice_column(); + let num_rows_inv = meta.advice_column(); let q_step_first = meta.complex_selector(); let q_step_last = meta.complex_selector(); - let qs_byte_lookup = meta.advice_column(); let advices = [(); STEP_WIDTH].map(|_| meta.advice_column()); - let step_curr = Step::new(meta, qs_byte_lookup, advices, false); - let step_next = Step::new(meta, qs_byte_lookup, advices, true); - let mut independent_lookups = Vec::new(); - let mut presets_map = HashMap::new(); + let step_curr = Step::new(meta, advices, 0); + let mut height_map = HashMap::new(); meta.create_gate("Constrain execution state", |meta| { - let q_step = meta.query_selector(q_step); + let q_usable = meta.query_selector(q_usable); + let q_step = meta.query_advice(q_step, Rotation::cur()); let q_step_first = meta.query_selector(q_step_first); let q_step_last = meta.query_selector(q_step_last); @@ -230,68 +236,6 @@ impl ExecutionConfig { ) }); - // ExecutionState transition should be correct. - let execution_state_transition = { - let q_step_last = q_step_last.clone(); - iter::empty() - .chain( - [ - ( - "EndTx can only transit to BeginTx or EndBlock", - ExecutionState::EndTx, - vec![ExecutionState::BeginTx, ExecutionState::EndBlock], - ), - ( - "EndBlock can only transit to EndBlock", - ExecutionState::EndBlock, - vec![ExecutionState::EndBlock], - ), - ] - .map(|(name, from, to)| { - ( - name, - step_curr.execution_state_selector([from]) - * (1.expr() - step_next.execution_state_selector(to)), - ) - }), - ) - .chain( - [ - ( - "Only EndTx can transit to BeginTx", - ExecutionState::BeginTx, - vec![ExecutionState::EndTx], - ), - ( - "Only ExecutionState which halts or BeginTx can transit to EndTx", - ExecutionState::EndTx, - ExecutionState::iterator() - .filter(ExecutionState::halts) - .chain(iter::once(ExecutionState::BeginTx)) - .collect(), - ), - ( - "Only EndTx or EndBlock can transit to EndBlock", - ExecutionState::EndBlock, - vec![ExecutionState::EndTx, ExecutionState::EndBlock], - ), - ( - "Only ExecutionState which copies memory to memory can transit to CopyToMemory", - ExecutionState::CopyToMemory, - vec![ExecutionState::CopyToMemory, ExecutionState::CALLDATACOPY], - ), - ] - .map(|(name, to, from)| { - ( - name, - step_next.execution_state_selector([to]) - * (1.expr() - step_curr.execution_state_selector(from)), - ) - }), - ) - .map(move |(name, poly)| (name, (1.expr() - q_step_last.clone()) * poly)) - }; - let _first_step_check = { let begin_tx_selector = step_curr.execution_state_selector([ExecutionState::BeginTx]); @@ -312,52 +256,78 @@ impl ExecutionConfig { iter::once(sum_to_one) .chain(bool_checks) - .chain(execution_state_transition) - .map(move |(name, poly)| (name, q_step.clone() * poly)) - // TODO: Enable these after test of CALLDATACOPY is complete. - // .chain(first_step_check) - // .chain(last_step_check) + .map(move |(name, poly)| (name, q_usable.clone() * q_step.clone() * poly)) + // TODO: Enable these after test of CALLDATACOPY is complete. + // .chain(first_step_check) + // .chain(last_step_check) }); - // Use qs_byte_lookup as selector to do byte range lookup on each advice - // column. In this way, ExecutionGadget could enable the byte range - // lookup by enable qs_byte_lookup. - for advice in advices { - meta.lookup_any("Qs byte", |meta| { - let advice = meta.query_advice(advice, Rotation::cur()); - let qs_byte_lookup = meta.query_advice(qs_byte_lookup, Rotation::cur()); - - vec![ - qs_byte_lookup.clone() * FixedTableTag::Range256.expr(), - qs_byte_lookup * advice, - 0u64.expr(), - 0u64.expr(), - ] - .into_iter() - .zip(fixed_table.table_exprs(meta).to_vec().into_iter()) - .collect::>() + meta.create_gate("q_step", |meta| { + let q_usable = meta.query_selector(q_usable); + let q_step_first = meta.query_selector(q_step_first); + let q_step = meta.query_advice(q_step, Rotation::cur()); + let num_rows_left_cur = meta.query_advice(num_rows_until_next_step, Rotation::cur()); + let num_rows_left_next = meta.query_advice(num_rows_until_next_step, Rotation::next()); + let num_rows_left_inverse = meta.query_advice(num_rows_inv, Rotation::cur()); + + let mut cb = BaseConstraintBuilder::default(); + // q_step needs to be enabled on the first row + cb.condition(q_step_first, |cb| { + cb.require_equal("q_step == 1", q_step.clone(), 1.expr()); }); - } + // Except when step is enabled, the step counter needs to decrease by 1 + cb.condition(1.expr() - q_step.clone(), |cb| { + cb.require_equal( + "num_rows_left_cur := num_rows_left_next + 1", + num_rows_left_cur.clone(), + num_rows_left_next + 1.expr(), + ); + }); + // Enforce that q_step := num_rows_until_next_step == 0 + let is_zero = 1.expr() - (num_rows_left_cur.clone() * num_rows_left_inverse.clone()); + cb.require_zero( + "num_rows_left_cur * is_zero == 0", + num_rows_left_cur * is_zero.clone(), + ); + cb.require_zero( + "num_rows_left_inverse * is_zero == 0", + num_rows_left_inverse * is_zero.clone(), + ); + cb.require_equal("q_step == is_zero", q_step, is_zero); + // On each usable row + cb.gate(q_usable) + }); + let mut stored_expressions_map = HashMap::new(); + let step_next = Step::new(meta, advices, MAX_STEP_HEIGHT); macro_rules! configure_gadget { () => { Self::configure_gadget( meta, + advices, + q_usable, q_step, + num_rows_until_next_step, q_step_first, + q_step_last, &power_of_randomness, &step_curr, &step_next, - &mut independent_lookups, - &mut presets_map, + &mut height_map, + &mut stored_expressions_map, ) }; } + let cell_manager = step_curr.cell_manager.clone(); let config = Self { + q_usable, q_step, + num_rows_until_next_step, + num_rows_inv, q_step_first, q_step_last, + advices, // internal states begin_tx_gadget: configure_gadget!(), copy_code_to_memory_gadget: configure_gadget!(), @@ -409,154 +379,238 @@ impl ExecutionConfig { // step and presets step: step_curr, - presets_map, + height_map, + stored_expressions_map, }; Self::configure_lookup( meta, - q_step, fixed_table, + byte_table, tx_table, rw_table, bytecode_table, block_table, - independent_lookups, + &power_of_randomness, + &cell_manager, ); config } + pub fn get_step_height(&self, execution_state: ExecutionState) -> usize { + *self + .height_map + .get(&execution_state) + .unwrap_or_else(|| panic!("Execution state unknown: {:?}", execution_state)) + } + #[allow(clippy::too_many_arguments)] fn configure_gadget>( meta: &mut ConstraintSystem, - q_step: Selector, + advices: [Column; STEP_WIDTH], + q_usable: Selector, + q_step: Column, + num_rows_until_next_step: Column, q_step_first: Selector, + q_step_last: Selector, power_of_randomness: &[Expression; 31], step_curr: &Step, step_next: &Step, - independent_lookups: &mut Vec>>, - presets_map: &mut HashMap>>, + height_map: &mut HashMap, + stored_expressions_map: &mut HashMap>>, ) -> G { + // Configure the gadget with the max height first so we can find out the actual + // height + let height = { + let mut cb = ConstraintBuilder::new( + step_curr.clone(), + step_next.clone(), + power_of_randomness, + G::EXECUTION_STATE, + ); + G::configure(&mut cb); + let (_, _, _, height) = cb.build(); + height + }; + + // Now actually configure the gadget with the correct minimal height + let step_next = &Step::new(meta, advices, height); let mut cb = ConstraintBuilder::new( - step_curr, - step_next, + step_curr.clone(), + step_next.clone(), power_of_randomness, G::EXECUTION_STATE, ); let gadget = G::configure(&mut cb); - let (constraints, constraints_first_step, lookups, presets) = cb.build(); + // Enforce the step height for this opcode + let mut num_rows_until_next_step_next = 0.expr(); + meta.create_gate("query num rows", |meta| { + num_rows_until_next_step_next = + meta.query_advice(num_rows_until_next_step, Rotation::next()); + vec![0.expr()] + }); + cb.require_equal( + "num_rows_until_next_step_next := height - 1", + num_rows_until_next_step_next, + (height - 1).expr(), + ); + + let (constraints, constraints_first_step, stored_expressions, _) = cb.build(); + debug_assert!( + !height_map.contains_key(&G::EXECUTION_STATE), + "execution state already configured" + ); + height_map.insert(G::EXECUTION_STATE, height); debug_assert!( - !presets_map.contains_key(&G::EXECUTION_STATE), + !stored_expressions_map.contains_key(&G::EXECUTION_STATE), "execution state already configured" ); - presets_map.insert(G::EXECUTION_STATE, presets); + stored_expressions_map.insert(G::EXECUTION_STATE, stored_expressions); + // Enforce the logic for this opcode + let q_steps: &dyn Fn(&mut VirtualCells) -> Expression = + &|meta| meta.query_advice(q_step, Rotation::cur()); + let q_steps_first: &dyn Fn(&mut VirtualCells) -> Expression = + &|meta| meta.query_selector(q_step_first); for (selector, constraints) in [ - (q_step, constraints), - (q_step_first, constraints_first_step), + (q_steps, constraints), + (q_steps_first, constraints_first_step), ] { if !constraints.is_empty() { meta.create_gate(G::NAME, |meta| { - let selector = meta.query_selector(selector); - - constraints - .into_iter() - .map(move |(name, constraint)| (name, selector.clone() * constraint)) + let q_usable = meta.query_selector(q_usable); + let selector = selector(meta); + constraints.into_iter().map(move |(name, constraint)| { + (name, q_usable.clone() * selector.clone() * constraint) + }) }); } } - // Push lookups of this ExecutionState to independent_lookups for - // further configuration in configure_lookup. - independent_lookups.push(lookups.iter().map(|(_, lookup)| lookup.clone()).collect()); + // Enforce the state transitions for this opcode + meta.create_gate("Constrain state machine transitions", |meta| { + let q_usable = meta.query_selector(q_usable); + let q_step = meta.query_advice(q_step, Rotation::cur()); + let q_step_last = meta.query_selector(q_step_last); + + // ExecutionState transition should be correct. + iter::empty() + .chain( + IntoIterator::into_iter([ + ( + "EndTx can only transit to BeginTx or EndBlock", + ExecutionState::EndTx, + vec![ExecutionState::BeginTx, ExecutionState::EndBlock], + ), + ( + "EndBlock can only transit to EndBlock", + ExecutionState::EndBlock, + vec![ExecutionState::EndBlock], + ), + ]) + .filter(move |(_, from, _)| *from == G::EXECUTION_STATE) + .map(|(_, _, to)| { + 1.expr() - step_next.execution_state_selector(to) + }), + ) + .chain( + IntoIterator::into_iter([ + ( + "Only EndTx can transit to BeginTx", + ExecutionState::BeginTx, + vec![ExecutionState::EndTx], + ), + ( + "Only ExecutionState which halts or BeginTx can transit to EndTx", + ExecutionState::EndTx, + ExecutionState::iterator() + .filter(ExecutionState::halts) + .chain(iter::once(ExecutionState::BeginTx)) + .collect(), + ), + ( + "Only EndTx or EndBlock can transit to EndBlock", + ExecutionState::EndBlock, + vec![ExecutionState::EndTx, ExecutionState::EndBlock], + ), + ( + "Only ExecutionState which copies memory to memory can transit to CopyToMemory", + ExecutionState::CopyToMemory, + vec![ExecutionState::CopyToMemory, ExecutionState::CALLDATACOPY], + ), + ]) + .filter(move |(_, _, from)| !from.contains(&G::EXECUTION_STATE)) + .map(|(_, to, _)| { + step_next.execution_state_selector([to]) + }), + ) + // Accumulate all state transition checks. + // This can be done because all summed values are enforced to be boolean. + .reduce(|accum, poly| accum + poly) + .map(move |poly| { + q_usable.clone() + * q_step.clone() + * (1.expr() - q_step_last.clone()) + * step_curr.execution_state_selector([G::EXECUTION_STATE]) + * poly + }) + }); gadget } #[allow(clippy::too_many_arguments)] - fn configure_lookup( + fn configure_lookup( meta: &mut ConstraintSystem, - q_step: Selector, - fixed_table: [Column; 4], - tx_table: TxTable, - rw_table: RwTable, - bytecode_table: BytecodeTable, - block_table: BlockTable, - independent_lookups: Vec>>, - ) where - TxTable: LookupTable, - RwTable: LookupTable, - BytecodeTable: LookupTable, - BlockTable: LookupTable, - { - // Because one and only one ExecutionState is enabled at a step, we then - // know only one of independent_lookups will be enabled at a step, so we - // can add up them together to reduce the amount of lookup arguments. - // This map holds all added up independent lookups as accumulated - // lookups, and will be used in configuring lookup arguments later. - let mut acc_lookups_of_table = HashMap::new(); - - for lookups in independent_lookups { - let mut index_of_table = HashMap::new(); - - for lookup in lookups { - let table = lookup.table(); - let acc_lookups = acc_lookups_of_table.entry(table).or_insert_with(Vec::new); - let index = index_of_table.entry(table).or_insert(0); - - if *index == acc_lookups.len() { - acc_lookups.push(lookup.input_exprs()); - } else { - // Add up independent lookup together - for (acc, expr) in acc_lookups[*index] - .iter_mut() - .zip(lookup.input_exprs().into_iter()) - { - *acc = acc.clone() + expr; + fixed_table: &dyn LookupTable, + byte_table: &dyn LookupTable, + tx_table: &dyn LookupTable, + rw_table: &dyn LookupTable, + bytecode_table: &dyn LookupTable, + block_table: &dyn LookupTable, + power_of_randomness: &[Expression; 31], + cell_manager: &CellManager, + ) { + for column in cell_manager.columns().iter() { + if let CellType::Lookup(table) = column.cell_type { + let name = format!("{:?}", table); + meta.lookup_any(Box::leak(name.into_boxed_str()), |meta| { + let table_expressions = match table { + Table::Fixed => fixed_table, + Table::Tx => tx_table, + Table::Rw => rw_table, + Table::Bytecode => bytecode_table, + Table::Block => block_table, + Table::Byte => byte_table, } - } - *index += 1; + .table_exprs(meta); + vec![( + column.expr(), + rlc::expr(&table_expressions, power_of_randomness), + )] + }); } } - - macro_rules! lookup { - ($id:path, $table:ident, $descrip:expr) => { - if let Some(acc_lookups) = acc_lookups_of_table.remove(&$id) { - for (lookup_idx, input_exprs) in acc_lookups.into_iter().enumerate() { - let idx = - meta.lookup_any(concat!("LOOKUP: ", stringify!($descrip)), |meta| { - let q_step = meta.query_selector(q_step); - input_exprs - .into_iter() - .zip($table.table_exprs(meta).to_vec().into_iter()) - .map(|(input, table)| (q_step.clone() * input, table)) - .collect::>() - }); - log::debug!( - "LOOKUP TABLE {} <=> {} {}", - idx, - stringify!($descrip), - lookup_idx - ); - } - } - }; - } - - lookup!(Table::Fixed, fixed_table, "Fixed table"); - lookup!(Table::Tx, tx_table, "Tx table"); - lookup!(Table::Rw, rw_table, "RW table"); - lookup!(Table::Bytecode, bytecode_table, "Bytecode table"); - lookup!(Table::Block, block_table, "Block table"); } + /// Assign block + /// When exact is enabled, assign exact steps in block without padding for + /// unit test purpose pub fn assign_block( &self, layouter: &mut impl Layouter, block: &Block, + _exact: bool, ) -> Result<(), Error> { + let power_of_randomness = (1..32) + .map(|exp| block.randomness.pow(&[exp, 0, 0, 0])) + .collect::>() + .try_into() + .unwrap(); + layouter.assign_region( || "Execution step", |mut region| { @@ -564,60 +618,133 @@ impl ExecutionConfig { self.q_step_first.enable(&mut region, offset)?; - for transaction in &block.txs { - for step in &transaction.steps { - let call = &transaction.calls[step.call_index]; - - self.q_step.enable(&mut region, offset)?; - self.assign_exec_step(&mut region, offset, block, transaction, call, step)?; - - offset += STEP_HEIGHT; + // Collect all steps + let mut steps = block + .txs + .iter() + .flat_map(|tx| tx.steps.iter().map(move |step| (tx, step))) + .peekable(); + + let mut last_height = 0; + while let Some((transaction, step)) = steps.next() { + let call = &transaction.calls[step.call_index]; + let height = self.get_step_height(step.execution_state); + + // Assign the step witness + self.assign_exec_step( + &mut region, + offset, + block, + transaction, + call, + step, + height, + steps.peek(), + power_of_randomness, + )?; + + // q_step logic + for idx in 0..height { + let offset = offset + idx; + self.q_usable.enable(&mut region, offset)?; + region.assign_advice( + || "step selector", + self.q_step, + offset, + || Ok(if idx == 0 { F::one() } else { F::zero() }), + )?; + let value = if idx == 0 { + F::zero() + } else { + F::from((height - idx) as u64) + }; + region.assign_advice( + || "step height", + self.num_rows_until_next_step, + offset, + || Ok(value), + )?; + region.assign_advice( + || "step height inv", + self.num_rows_inv, + offset, + || Ok(value.invert().unwrap_or(F::zero())), + )?; } + + offset += height; + last_height = height; } + // These are still referenced (but not used) in next rows + region.assign_advice( + || "step height", + self.num_rows_until_next_step, + offset, + || Ok(F::zero()), + )?; + region.assign_advice( + || "step height inv", + self.q_step, + offset, + || Ok(F::zero()), + )?; + + // If not exact: + // TODO: Pad leftover region to the desired capacity + // TODO: Enable q_step_last + self.q_step_last.enable(&mut region, offset - last_height)?; + Ok(()) }, - )?; - - // TODO: Pad leftover region to the desired capacity - // TODO: Enable q_step_last - - Ok(()) + ) } - /// Assign exact steps in block without padding for unit test purpose - pub fn assign_block_exact( + #[allow(clippy::too_many_arguments)] + fn assign_exec_step( &self, - layouter: &mut impl Layouter, + region: &mut Region<'_, F>, + offset: usize, block: &Block, + transaction: &Transaction, + call: &Call, + step: &ExecStep, + height: usize, + next: Option<&(&Transaction, &ExecStep)>, + power_of_randomness: [F; 31], ) -> Result<(), Error> { - layouter.assign_region( - || "Execution step", - |mut region| { - let mut offset = 0; - - self.q_step_first.enable(&mut region, offset)?; - - for transaction in &block.txs { - for step in &transaction.steps { - let call = &transaction.calls[step.call_index]; - - self.q_step.enable(&mut region, offset)?; - self.assign_exec_step(&mut region, offset, block, transaction, call, step)?; - - offset += STEP_HEIGHT; - } - } + // Make the region large enough for the current step and the next step. + // The next step's next step may also be accessed, so make the region large + // enough for 3 steps. + let region = &mut CachedRegion::<'_, '_, F>::new( + region, + power_of_randomness, + STEP_WIDTH, + MAX_STEP_HEIGHT * 3, + self.advices[0].index(), + offset, + ); - self.q_step_last.enable(&mut region, offset - STEP_HEIGHT)?; + // Also set the witness of the next step. + // These may be used in stored expressions and + // so their witness values need to be known to be able + // to correctly calculate the intermediate value. + if let Some((transaction_next, step_next)) = next { + self.assign_exec_step_int( + region, + offset + height, + block, + transaction_next, + call, + step_next, + )?; + } - Ok(()) - }, - ) + self.assign_exec_step_int(region, offset, block, transaction, call, step) } - fn assign_exec_step( + fn assign_exec_step_int( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, block: &Block, transaction: &Transaction, @@ -628,14 +755,6 @@ impl ExecutionConfig { self.step .assign_exec_step(region, offset, block, transaction, call, step)?; - for (cell, value) in self - .presets_map - .get(&step.execution_state) - .expect("not implemented") - { - cell.assign(region, offset, Some(*value))?; - } - macro_rules! assign_exec_step { ($gadget:expr) => { $gadget.assign_exec_step(region, offset, block, transaction, call, step)? @@ -696,6 +815,15 @@ impl ExecutionConfig { _ => unimplemented!(), } + // Fill in the witness values for stored expressions + for stored_expression in self + .stored_expressions_map + .get(&step.execution_state) + .unwrap_or_else(|| panic!("Execution state unknown: {:?}", step.execution_state)) + { + stored_expression.assign(region, offset)?; + } + Ok(()) } } diff --git a/zkevm-circuits/src/evm_circuit/execution/add_sub.rs b/zkevm-circuits/src/evm_circuit/execution/add_sub.rs index 2c5f2da262..780735713c 100644 --- a/zkevm-circuits/src/evm_circuit/execution/add_sub.rs +++ b/zkevm-circuits/src/evm_circuit/execution/add_sub.rs @@ -6,7 +6,7 @@ use crate::{ common_gadget::SameContextGadget, constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, math_gadget::{AddWordsGadget, PairSelectGadget}, - select, + select, CachedRegion, }, witness::{Block, Call, ExecStep, Transaction}, }, @@ -14,7 +14,7 @@ use crate::{ }; use bus_mapping::evm::OpcodeId; use eth_types::Field; -use halo2_proofs::{circuit::Region, plonk::Error}; +use halo2_proofs::plonk::Error; // AddGadget verifies ADD and SUB at the same time by an extra swap flag, // when it's ADD, we annotate stack as [a, b, ...] and [c, ...], @@ -73,7 +73,7 @@ impl ExecutionGadget for AddSubGadget { fn assign_exec_step( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, block: &Block, _: &Transaction, diff --git a/zkevm-circuits/src/evm_circuit/execution/begin_tx.rs b/zkevm-circuits/src/evm_circuit/execution/begin_tx.rs index aa06e672ca..432cf32623 100644 --- a/zkevm-circuits/src/evm_circuit/execution/begin_tx.rs +++ b/zkevm-circuits/src/evm_circuit/execution/begin_tx.rs @@ -11,14 +11,14 @@ use crate::{ Transition::{Delta, To}, }, math_gadget::{MulWordByU64Gadget, RangeCheckGadget}, - select, Cell, RandomLinearCombination, Word, + select, CachedRegion, Cell, RandomLinearCombination, Word, }, witness::{Block, Call, ExecStep, Transaction}, }, util::Expr, }; use eth_types::{evm_types::GasCost, Field, ToLittleEndian, ToScalar}; -use halo2_proofs::{circuit::Region, plonk::Error}; +use halo2_proofs::plonk::Error; #[derive(Clone, Debug)] pub(crate) struct BeginTxGadget { @@ -212,7 +212,7 @@ impl ExecutionGadget for BeginTxGadget { fn assign_exec_step( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, block: &Block, tx: &Transaction, diff --git a/zkevm-circuits/src/evm_circuit/execution/bitwise.rs b/zkevm-circuits/src/evm_circuit/execution/bitwise.rs index 1dc4d508f7..09e3d917c5 100644 --- a/zkevm-circuits/src/evm_circuit/execution/bitwise.rs +++ b/zkevm-circuits/src/evm_circuit/execution/bitwise.rs @@ -6,7 +6,7 @@ use crate::{ util::{ common_gadget::SameContextGadget, constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, - Word, + CachedRegion, Word, }, witness::{Block, Call, ExecStep, Transaction}, }, @@ -15,7 +15,7 @@ use crate::{ use eth_types::evm_types::OpcodeId; use eth_types::Field; use eth_types::ToLittleEndian; -use halo2_proofs::{circuit::Region, plonk::Error}; +use halo2_proofs::plonk::Error; #[derive(Clone, Debug)] pub(crate) struct BitwiseGadget { @@ -80,7 +80,7 @@ impl ExecutionGadget for BitwiseGadget { fn assign_exec_step( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, block: &Block, _: &Transaction, diff --git a/zkevm-circuits/src/evm_circuit/execution/block_ctx.rs b/zkevm-circuits/src/evm_circuit/execution/block_ctx.rs index 943df2604e..56115f070c 100644 --- a/zkevm-circuits/src/evm_circuit/execution/block_ctx.rs +++ b/zkevm-circuits/src/evm_circuit/execution/block_ctx.rs @@ -7,7 +7,7 @@ use crate::{ util::{ common_gadget::SameContextGadget, constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, - from_bytes, RandomLinearCombination, + from_bytes, CachedRegion, RandomLinearCombination, }, witness::{Block, Call, ExecStep, Transaction}, }, @@ -16,7 +16,7 @@ use crate::{ use bus_mapping::evm::OpcodeId; use eth_types::Field; use eth_types::ToLittleEndian; -use halo2_proofs::{circuit::Region, plonk::Error}; +use halo2_proofs::plonk::Error; use std::convert::{TryFrom, TryInto}; #[derive(Clone, Debug)] @@ -81,7 +81,7 @@ impl ExecutionGadget for BlockCtxU64Gadget { fn assign_exec_step( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, block: &Block, _: &Transaction, @@ -122,7 +122,7 @@ impl ExecutionGadget for BlockCtxU160Gadget { fn assign_exec_step( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, block: &Block, _: &Transaction, @@ -167,7 +167,7 @@ impl ExecutionGadget for BlockCtxU256Gadget { fn assign_exec_step( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, block: &Block, _: &Transaction, diff --git a/zkevm-circuits/src/evm_circuit/execution/byte.rs b/zkevm-circuits/src/evm_circuit/execution/byte.rs index 670493c1ae..0336d3a6a0 100644 --- a/zkevm-circuits/src/evm_circuit/execution/byte.rs +++ b/zkevm-circuits/src/evm_circuit/execution/byte.rs @@ -6,7 +6,7 @@ use crate::{ common_gadget::SameContextGadget, constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, math_gadget::{IsEqualGadget, IsZeroGadget}, - sum, Word, + sum, CachedRegion, Word, }, witness::{Block, Call, ExecStep, Transaction}, }, @@ -16,7 +16,7 @@ use array_init::array_init; use bus_mapping::evm::OpcodeId; use eth_types::Field; use eth_types::ToLittleEndian; -use halo2_proofs::{circuit::Region, plonk::Error}; +use halo2_proofs::plonk::Error; #[derive(Clone, Debug)] pub(crate) struct ByteGadget { @@ -92,7 +92,7 @@ impl ExecutionGadget for ByteGadget { fn assign_exec_step( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, block: &Block, _: &Transaction, diff --git a/zkevm-circuits/src/evm_circuit/execution/call.rs b/zkevm-circuits/src/evm_circuit/execution/call.rs index 4cec02bc87..10295224bc 100644 --- a/zkevm-circuits/src/evm_circuit/execution/call.rs +++ b/zkevm-circuits/src/evm_circuit/execution/call.rs @@ -3,7 +3,7 @@ use crate::{ execution::ExecutionGadget, param::{N_BYTES_ACCOUNT_ADDRESS, N_BYTES_GAS, N_BYTES_MEMORY_WORD_SIZE}, step::ExecutionState, - table::{AccountFieldTag, CallContextFieldTag, FixedTableTag, Lookup}, + table::{AccountFieldTag, CallContextFieldTag}, util::{ common_gadget::TransferGadget, constraint_builder::{ @@ -16,17 +16,18 @@ use crate::{ MinMaxGadget, }, memory_gadget::{MemoryAddressGadget, MemoryExpansionGadget}, - select, sum, Cell, Word, + select, sum, CachedRegion, Cell, Word, }, witness::{Block, Call, ExecStep, Transaction}, }, util::Expr, }; +use bus_mapping::evm::OpcodeId; use eth_types::{ evm_types::{GasCost, GAS_STIPEND_CALL_WITH_VALUE}, Field, ToLittleEndian, ToScalar, }; -use halo2_proofs::{circuit::Region, plonk::Error}; +use halo2_proofs::plonk::Error; use keccak256::EMPTY_HASH_LE; #[derive(Clone, Debug)] @@ -67,18 +68,12 @@ impl ExecutionGadget for CallGadget { let opcode = cb.query_cell(); cb.opcode_lookup(opcode.expr(), 1.expr()); - // We do the `ResponsibleOpcode` lookup explicitly here because we're not using + // We do the responsible opcode check explicitly here because we're not using // the `SameContextGadget` for `CALL`. - cb.add_lookup( - "Responsible opcode lookup", - Lookup::Fixed { - tag: FixedTableTag::ResponsibleOpcode.expr(), - values: [ - cb.execution_state().as_u64().expr(), - opcode.expr(), - 0.expr(), - ], - }, + cb.require_equal( + "Opcode should be CALL", + opcode.expr(), + OpcodeId::CALL.expr(), ); let gas_word = cb.query_word(); @@ -337,7 +332,7 @@ impl ExecutionGadget for CallGadget { fn assign_exec_step( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, block: &Block, _: &Transaction, @@ -692,13 +687,23 @@ mod test { #[test] fn call_gadget_recursive() { test_ok( - caller( - Stack { - gas: 100000, - ..Default::default() - }, - false, - ), + Account { + address: Address::repeat_byte(0xfe), + balance: Word::from(10).pow(20.into()), + code: bytecode! { + PUSH1(0) + PUSH1(0) + PUSH1(0) + PUSH1(0) + PUSH1(0) + PUSH32(Address::repeat_byte(0xff).to_word()) + PUSH2(10000) + CALL + STOP + } + .into(), + ..Default::default() + }, // The following bytecode calls itself recursively if gas_left is greater than 100, and // halts with REVERT if gas_left is odd, otherwise just halts with STOP. callee(bytecode! { diff --git a/zkevm-circuits/src/evm_circuit/execution/calldatacopy.rs b/zkevm-circuits/src/evm_circuit/execution/calldatacopy.rs index 6e3fc3aeb7..327279607d 100644 --- a/zkevm-circuits/src/evm_circuit/execution/calldatacopy.rs +++ b/zkevm-circuits/src/evm_circuit/execution/calldatacopy.rs @@ -12,7 +12,7 @@ use crate::{ }, from_bytes, memory_gadget::{MemoryAddressGadget, MemoryCopierGasGadget, MemoryExpansionGadget}, - Cell, MemoryAddress, + CachedRegion, Cell, MemoryAddress, }, witness::{Block, Call, ExecStep, Transaction}, }, @@ -21,7 +21,8 @@ use crate::{ use bus_mapping::evm::OpcodeId; use eth_types::Field; use eth_types::ToLittleEndian; -use halo2_proofs::{circuit::Region, plonk::Error}; +use halo2_proofs::plonk::Error; + use std::convert::TryInto; #[derive(Clone, Debug)] @@ -175,7 +176,7 @@ impl ExecutionGadget for CallDataCopyGadget { fn assign_exec_step( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, block: &Block, tx: &Transaction, diff --git a/zkevm-circuits/src/evm_circuit/execution/calldataload.rs b/zkevm-circuits/src/evm_circuit/execution/calldataload.rs index 5e647e553e..7a4f7c6679 100644 --- a/zkevm-circuits/src/evm_circuit/execution/calldataload.rs +++ b/zkevm-circuits/src/evm_circuit/execution/calldataload.rs @@ -2,10 +2,7 @@ use std::convert::TryInto; use bus_mapping::evm::OpcodeId; use eth_types::{Field, ToLittleEndian}; -use halo2_proofs::{ - circuit::Region, - plonk::{Error, Expression}, -}; +use halo2_proofs::plonk::{Error, Expression}; use crate::{ evm_circuit::{ @@ -16,7 +13,7 @@ use crate::{ common_gadget::SameContextGadget, constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, memory_gadget::BufferReaderGadget, - Cell, MemoryAddress, RandomLinearCombination, + CachedRegion, Cell, MemoryAddress, RandomLinearCombination, }, witness::{Block, Call, ExecStep, Transaction}, }, @@ -171,7 +168,7 @@ impl ExecutionGadget for CallDataLoadGadget { fn assign_exec_step( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, block: &Block, tx: &Transaction, diff --git a/zkevm-circuits/src/evm_circuit/execution/calldatasize.rs b/zkevm-circuits/src/evm_circuit/execution/calldatasize.rs index 2f34d38868..c8ef0af926 100644 --- a/zkevm-circuits/src/evm_circuit/execution/calldatasize.rs +++ b/zkevm-circuits/src/evm_circuit/execution/calldatasize.rs @@ -7,7 +7,7 @@ use crate::{ util::{ common_gadget::SameContextGadget, constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, - from_bytes, RandomLinearCombination, + from_bytes, CachedRegion, RandomLinearCombination, }, witness::{Block, Call, ExecStep, Transaction}, }, @@ -15,7 +15,8 @@ use crate::{ }; use bus_mapping::evm::OpcodeId; use eth_types::{Field, ToLittleEndian}; -use halo2_proofs::{circuit::Region, plonk::Error}; +use halo2_proofs::plonk::Error; + use std::convert::TryInto; #[derive(Clone, Debug)] @@ -62,7 +63,7 @@ impl ExecutionGadget for CallDataSizeGadget { fn assign_exec_step( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, block: &Block, _tx: &Transaction, diff --git a/zkevm-circuits/src/evm_circuit/execution/caller.rs b/zkevm-circuits/src/evm_circuit/execution/caller.rs index 19c273c2ba..2bb0e22fa7 100644 --- a/zkevm-circuits/src/evm_circuit/execution/caller.rs +++ b/zkevm-circuits/src/evm_circuit/execution/caller.rs @@ -7,7 +7,7 @@ use crate::{ util::{ common_gadget::SameContextGadget, constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, - from_bytes, RandomLinearCombination, + from_bytes, CachedRegion, RandomLinearCombination, }, witness::{Block, Call, ExecStep, Transaction}, }, @@ -15,7 +15,8 @@ use crate::{ }; use bus_mapping::evm::OpcodeId; use eth_types::{Field, ToLittleEndian}; -use halo2_proofs::{circuit::Region, plonk::Error}; +use halo2_proofs::plonk::Error; + use std::convert::TryInto; #[derive(Clone, Debug)] @@ -63,7 +64,7 @@ impl ExecutionGadget for CallerGadget { fn assign_exec_step( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, block: &Block, _: &Transaction, diff --git a/zkevm-circuits/src/evm_circuit/execution/callvalue.rs b/zkevm-circuits/src/evm_circuit/execution/callvalue.rs index 274ff18b1a..989a158d09 100644 --- a/zkevm-circuits/src/evm_circuit/execution/callvalue.rs +++ b/zkevm-circuits/src/evm_circuit/execution/callvalue.rs @@ -6,7 +6,7 @@ use crate::{ util::{ common_gadget::SameContextGadget, constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, - Cell, Word, + CachedRegion, Cell, Word, }, witness::{Block, Call, ExecStep, Transaction}, }, @@ -14,7 +14,7 @@ use crate::{ }; use bus_mapping::evm::OpcodeId; use eth_types::{Field, ToLittleEndian}; -use halo2_proofs::{circuit::Region, plonk::Error}; +use halo2_proofs::plonk::Error; #[derive(Clone, Debug)] pub(crate) struct CallValueGadget { @@ -62,7 +62,7 @@ impl ExecutionGadget for CallValueGadget { fn assign_exec_step( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, block: &Block, _: &Transaction, diff --git a/zkevm-circuits/src/evm_circuit/execution/chainid.rs b/zkevm-circuits/src/evm_circuit/execution/chainid.rs index 98eb170f0e..184fb4c843 100644 --- a/zkevm-circuits/src/evm_circuit/execution/chainid.rs +++ b/zkevm-circuits/src/evm_circuit/execution/chainid.rs @@ -6,7 +6,7 @@ use crate::{ util::{ common_gadget::SameContextGadget, constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, - Cell, Word, + CachedRegion, Cell, Word, }, witness::{Block, Call, ExecStep, Transaction}, }, @@ -14,7 +14,7 @@ use crate::{ }; use bus_mapping::evm::OpcodeId; use eth_types::{Field, ToLittleEndian}; -use halo2_proofs::{circuit::Region, plonk::Error}; +use halo2_proofs::plonk::Error; #[derive(Clone, Debug)] pub(crate) struct ChainIdGadget { @@ -55,7 +55,7 @@ impl ExecutionGadget for ChainIdGadget { fn assign_exec_step( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, block: &Block, _: &Transaction, diff --git a/zkevm-circuits/src/evm_circuit/execution/codecopy.rs b/zkevm-circuits/src/evm_circuit/execution/codecopy.rs index 09edaab597..9b99e85bb1 100644 --- a/zkevm-circuits/src/evm_circuit/execution/codecopy.rs +++ b/zkevm-circuits/src/evm_circuit/execution/codecopy.rs @@ -2,7 +2,7 @@ use std::convert::TryInto; use bus_mapping::evm::OpcodeId; use eth_types::{Field, ToLittleEndian}; -use halo2_proofs::{circuit::Region, plonk::Error}; +use halo2_proofs::plonk::Error; use crate::{ evm_circuit::{ @@ -13,7 +13,7 @@ use crate::{ constraint_builder::{ConstraintBuilder, StepStateTransition, Transition}, from_bytes, memory_gadget::{MemoryAddressGadget, MemoryCopierGasGadget, MemoryExpansionGadget}, - Cell, MemoryAddress, + CachedRegion, Cell, MemoryAddress, }, witness::{Block, Call, CodeSource, ExecStep, Transaction}, }, @@ -146,7 +146,7 @@ impl ExecutionGadget for CodeCopyGadget { fn assign_exec_step( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, block: &Block, _tx: &Transaction, diff --git a/zkevm-circuits/src/evm_circuit/execution/coinbase.rs b/zkevm-circuits/src/evm_circuit/execution/coinbase.rs index a256b74cc5..084b52b371 100644 --- a/zkevm-circuits/src/evm_circuit/execution/coinbase.rs +++ b/zkevm-circuits/src/evm_circuit/execution/coinbase.rs @@ -7,7 +7,7 @@ use crate::{ util::{ common_gadget::SameContextGadget, constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, - from_bytes, RandomLinearCombination, + from_bytes, CachedRegion, RandomLinearCombination, }, witness::{Block, Call, ExecStep, Transaction}, }, @@ -16,7 +16,8 @@ use crate::{ use bus_mapping::evm::OpcodeId; use eth_types::Field; use eth_types::ToLittleEndian; -use halo2_proofs::{circuit::Region, plonk::Error}; +use halo2_proofs::plonk::Error; + use std::convert::TryInto; #[derive(Clone, Debug)] @@ -62,7 +63,7 @@ impl ExecutionGadget for CoinbaseGadget { fn assign_exec_step( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, block: &Block, _: &Transaction, diff --git a/zkevm-circuits/src/evm_circuit/execution/comparator.rs b/zkevm-circuits/src/evm_circuit/execution/comparator.rs index 3880b780e1..b5dc7a56d7 100644 --- a/zkevm-circuits/src/evm_circuit/execution/comparator.rs +++ b/zkevm-circuits/src/evm_circuit/execution/comparator.rs @@ -7,14 +7,14 @@ use crate::{ constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, from_bytes, math_gadget::{ComparisonGadget, IsEqualGadget}, - select, Cell, Word, + select, CachedRegion, Cell, Word, }, witness::{Block, Call, ExecStep, Transaction}, }, util::Expr, }; use eth_types::{evm_types::OpcodeId, Field, ToLittleEndian}; -use halo2_proofs::{circuit::Region, plonk::Error}; +use halo2_proofs::plonk::Error; #[derive(Clone, Debug)] pub(crate) struct ComparatorGadget { @@ -106,7 +106,7 @@ impl ExecutionGadget for ComparatorGadget { fn assign_exec_step( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, block: &Block, _: &Transaction, diff --git a/zkevm-circuits/src/evm_circuit/execution/copy_code_to_memory.rs b/zkevm-circuits/src/evm_circuit/execution/copy_code_to_memory.rs index a9a9168c9f..0b31c9cb58 100644 --- a/zkevm-circuits/src/evm_circuit/execution/copy_code_to_memory.rs +++ b/zkevm-circuits/src/evm_circuit/execution/copy_code_to_memory.rs @@ -1,7 +1,7 @@ use array_init::array_init; use bus_mapping::{circuit_input_builder::CopyDetails, constants::MAX_COPY_BYTES}; use eth_types::{Field, ToLittleEndian}; -use halo2_proofs::{circuit::Region, plonk::Error}; +use halo2_proofs::plonk::Error; use crate::{ evm_circuit::{ @@ -11,7 +11,7 @@ use crate::{ constraint_builder::{ConstraintBuilder, StepStateTransition, Transition}, math_gadget::ComparisonGadget, memory_gadget::BufferReaderGadget, - Cell, Word, + CachedRegion, Cell, Word, }, witness::{Block, Call, ExecStep, Transaction}, }, @@ -165,7 +165,7 @@ impl ExecutionGadget for CopyCodeToMemoryGadget { fn assign_exec_step( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, block: &Block, _tx: &Transaction, diff --git a/zkevm-circuits/src/evm_circuit/execution/copy_to_log.rs b/zkevm-circuits/src/evm_circuit/execution/copy_to_log.rs index b477f6b294..2876bc2b3a 100644 --- a/zkevm-circuits/src/evm_circuit/execution/copy_to_log.rs +++ b/zkevm-circuits/src/evm_circuit/execution/copy_to_log.rs @@ -8,7 +8,7 @@ use crate::{ constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, math_gadget::ComparisonGadget, memory_gadget::BufferReaderGadget, - Cell, + CachedRegion, Cell, }, witness::{Block, Call, ExecStep, Transaction}, }, @@ -16,7 +16,7 @@ use crate::{ }; use bus_mapping::{circuit_input_builder::CopyDetails, constants::MAX_COPY_BYTES}; use eth_types::Field; -use halo2_proofs::{circuit::Region, plonk::Error}; +use halo2_proofs::plonk::Error; /// Multi-step gadget for copying data from memory to RW log #[derive(Clone, Debug)] @@ -126,7 +126,7 @@ impl ExecutionGadget for CopyToLogGadget { fn assign_exec_step( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, block: &Block, _: &Transaction, diff --git a/zkevm-circuits/src/evm_circuit/execution/dup.rs b/zkevm-circuits/src/evm_circuit/execution/dup.rs index d18346d154..11fb48b264 100644 --- a/zkevm-circuits/src/evm_circuit/execution/dup.rs +++ b/zkevm-circuits/src/evm_circuit/execution/dup.rs @@ -5,14 +5,14 @@ use crate::{ util::{ common_gadget::SameContextGadget, constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, - Cell, Word, + CachedRegion, Cell, Word, }, witness::{Block, Call, ExecStep, Transaction}, }, util::Expr, }; use eth_types::{evm_types::OpcodeId, Field, ToLittleEndian}; -use halo2_proofs::{circuit::Region, plonk::Error}; +use halo2_proofs::plonk::Error; #[derive(Clone, Debug)] pub(crate) struct DupGadget { @@ -56,7 +56,7 @@ impl ExecutionGadget for DupGadget { fn assign_exec_step( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, block: &Block, _: &Transaction, diff --git a/zkevm-circuits/src/evm_circuit/execution/end_block.rs b/zkevm-circuits/src/evm_circuit/execution/end_block.rs index 85e0c7a949..665f42b03a 100644 --- a/zkevm-circuits/src/evm_circuit/execution/end_block.rs +++ b/zkevm-circuits/src/evm_circuit/execution/end_block.rs @@ -1,11 +1,12 @@ use crate::evm_circuit::{ execution::ExecutionGadget, step::ExecutionState, - util::constraint_builder::ConstraintBuilder, + util::{constraint_builder::ConstraintBuilder, CachedRegion}, witness::{Block, Call, ExecStep, Transaction}, }; use eth_types::Field; -use halo2_proofs::{circuit::Region, plonk::Error}; +use halo2_proofs::plonk::Error; + use std::marker::PhantomData; #[derive(Clone, Debug)] @@ -32,7 +33,7 @@ impl ExecutionGadget for EndBlockGadget { fn assign_exec_step( &self, - _region: &mut Region<'_, F>, + _region: &mut CachedRegion<'_, '_, F>, _offset: usize, _: &Block, _: &Transaction, diff --git a/zkevm-circuits/src/evm_circuit/execution/end_tx.rs b/zkevm-circuits/src/evm_circuit/execution/end_tx.rs index fb8606fd6c..661facb443 100644 --- a/zkevm-circuits/src/evm_circuit/execution/end_tx.rs +++ b/zkevm-circuits/src/evm_circuit/execution/end_tx.rs @@ -14,14 +14,14 @@ use crate::{ AddWordsGadget, ConstantDivisionGadget, IsEqualGadget, MinMaxGadget, MulWordByU64Gadget, }, - Cell, + CachedRegion, Cell, }, witness::{Block, Call, ExecStep, Transaction}, }, util::Expr, }; use eth_types::{evm_types::MAX_REFUND_QUOTIENT_OF_GAS_USED, Field, ToScalar}; -use halo2_proofs::{circuit::Region, plonk::Error}; +use halo2_proofs::plonk::Error; #[derive(Clone, Debug)] pub(crate) struct EndTxGadget { @@ -185,7 +185,7 @@ impl ExecutionGadget for EndTxGadget { fn assign_exec_step( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, block: &Block, tx: &Transaction, diff --git a/zkevm-circuits/src/evm_circuit/execution/error_oog_static_memory.rs b/zkevm-circuits/src/evm_circuit/execution/error_oog_static_memory.rs index 935a0c4ddc..8ba6fdc1d5 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_oog_static_memory.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_oog_static_memory.rs @@ -7,14 +7,14 @@ use crate::{ constraint_builder::ConstraintBuilder, math_gadget::{IsEqualGadget, IsZeroGadget, RangeCheckGadget}, memory_gadget::{address_high, address_low, MemoryExpansionGadget}, - Cell, Word, + CachedRegion, Cell, Word, }, witness::{Block, Call, ExecStep, Transaction}, }, util::Expr, }; use eth_types::{evm_types::OpcodeId, Field, ToLittleEndian}; -use halo2_proofs::{circuit::Region, plonk::Error}; +use halo2_proofs::plonk::Error; #[derive(Clone, Debug)] pub(crate) struct ErrorOOGStaticMemoryGadget { @@ -89,7 +89,7 @@ impl ExecutionGadget for ErrorOOGStaticMemoryGadget { fn assign_exec_step( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, block: &Block, _: &Transaction, diff --git a/zkevm-circuits/src/evm_circuit/execution/extcodehash.rs b/zkevm-circuits/src/evm_circuit/execution/extcodehash.rs index d772d1d5fe..64a712e749 100644 --- a/zkevm-circuits/src/evm_circuit/execution/extcodehash.rs +++ b/zkevm-circuits/src/evm_circuit/execution/extcodehash.rs @@ -11,14 +11,14 @@ use crate::{ }, from_bytes, math_gadget::BatchedIsZeroGadget, - Cell, RandomLinearCombination, Word, + CachedRegion, Cell, RandomLinearCombination, Word, }, witness::{Block, Call, ExecStep, Transaction}, }, util::Expr, }; use eth_types::{evm_types::GasCost, Field, ToAddress, ToScalar, U256}; -use halo2_proofs::{circuit::Region, plonk::Error}; +use halo2_proofs::plonk::Error; use keccak256::EMPTY_HASH_LE; #[derive(Clone, Debug)] @@ -122,7 +122,7 @@ impl ExecutionGadget for ExtcodehashGadget { fn assign_exec_step( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, block: &Block, tx: &Transaction, diff --git a/zkevm-circuits/src/evm_circuit/execution/gas.rs b/zkevm-circuits/src/evm_circuit/execution/gas.rs index 2183831ca1..aa8fef3428 100644 --- a/zkevm-circuits/src/evm_circuit/execution/gas.rs +++ b/zkevm-circuits/src/evm_circuit/execution/gas.rs @@ -6,14 +6,14 @@ use crate::{ util::{ common_gadget::SameContextGadget, constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, - from_bytes, RandomLinearCombination, + from_bytes, CachedRegion, RandomLinearCombination, }, witness::{Block, Call, ExecStep, Transaction}, }, util::Expr, }; use eth_types::{evm_types::OpcodeId, Field}; -use halo2_proofs::{circuit::Region, plonk::Error}; +use halo2_proofs::plonk::Error; #[derive(Clone, Debug)] pub(crate) struct GasGadget { @@ -59,7 +59,7 @@ impl ExecutionGadget for GasGadget { fn assign_exec_step( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, _block: &Block, _transaction: &Transaction, diff --git a/zkevm-circuits/src/evm_circuit/execution/gasprice.rs b/zkevm-circuits/src/evm_circuit/execution/gasprice.rs index c16f758642..ef132b5a6d 100644 --- a/zkevm-circuits/src/evm_circuit/execution/gasprice.rs +++ b/zkevm-circuits/src/evm_circuit/execution/gasprice.rs @@ -6,7 +6,7 @@ use crate::{ util::{ common_gadget::SameContextGadget, constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, - Cell, Word, + CachedRegion, Cell, Word, }, witness::{Block, Call, ExecStep, Transaction}, }, @@ -14,7 +14,7 @@ use crate::{ }; use bus_mapping::evm::OpcodeId; use eth_types::{Field, ToLittleEndian}; -use halo2_proofs::{circuit::Region, plonk::Error}; +use halo2_proofs::plonk::Error; #[derive(Clone, Debug)] pub(crate) struct GasPriceGadget { @@ -65,7 +65,7 @@ impl ExecutionGadget for GasPriceGadget { fn assign_exec_step( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, block: &Block, tx: &Transaction, diff --git a/zkevm-circuits/src/evm_circuit/execution/is_zero.rs b/zkevm-circuits/src/evm_circuit/execution/is_zero.rs index 9e0d25e0ef..509849d3e3 100644 --- a/zkevm-circuits/src/evm_circuit/execution/is_zero.rs +++ b/zkevm-circuits/src/evm_circuit/execution/is_zero.rs @@ -5,7 +5,7 @@ use crate::{ util::{ common_gadget::SameContextGadget, constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, - math_gadget, Cell, Word, + math_gadget, CachedRegion, Cell, Word, }, witness::{Block, Call, ExecStep, Transaction}, }, @@ -13,7 +13,7 @@ use crate::{ }; use bus_mapping::evm::OpcodeId; use eth_types::{Field, ToLittleEndian}; -use halo2_proofs::{circuit::Region, plonk::Error}; +use halo2_proofs::plonk::Error; #[derive(Clone, Debug)] pub(crate) struct IsZeroGadget { @@ -55,7 +55,7 @@ impl ExecutionGadget for IsZeroGadget { fn assign_exec_step( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, block: &Block, _: &Transaction, diff --git a/zkevm-circuits/src/evm_circuit/execution/jump.rs b/zkevm-circuits/src/evm_circuit/execution/jump.rs index f03dd65af0..38aa26260f 100644 --- a/zkevm-circuits/src/evm_circuit/execution/jump.rs +++ b/zkevm-circuits/src/evm_circuit/execution/jump.rs @@ -9,14 +9,15 @@ use crate::{ ConstraintBuilder, StepStateTransition, Transition::{Delta, To}, }, - from_bytes, RandomLinearCombination, + from_bytes, CachedRegion, RandomLinearCombination, }, witness::{Block, Call, ExecStep, Transaction}, }, util::Expr, }; use eth_types::{evm_types::OpcodeId, Field, ToLittleEndian}; -use halo2_proofs::{circuit::Region, plonk::Error}; +use halo2_proofs::plonk::Error; + use std::convert::TryInto; #[derive(Clone, Debug)] @@ -62,7 +63,7 @@ impl ExecutionGadget for JumpGadget { fn assign_exec_step( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, block: &Block, _: &Transaction, diff --git a/zkevm-circuits/src/evm_circuit/execution/jumpdest.rs b/zkevm-circuits/src/evm_circuit/execution/jumpdest.rs index 43bb85647d..cedc4059a5 100644 --- a/zkevm-circuits/src/evm_circuit/execution/jumpdest.rs +++ b/zkevm-circuits/src/evm_circuit/execution/jumpdest.rs @@ -5,6 +5,7 @@ use crate::{ util::{ common_gadget::SameContextGadget, constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, + CachedRegion, }, witness::{Block, Call, ExecStep, Transaction}, }, @@ -12,7 +13,7 @@ use crate::{ }; use bus_mapping::evm::OpcodeId; use eth_types::Field; -use halo2_proofs::{circuit::Region, plonk::Error}; +use halo2_proofs::plonk::Error; #[derive(Clone, Debug)] pub(crate) struct JumpdestGadget { @@ -39,7 +40,7 @@ impl ExecutionGadget for JumpdestGadget { fn assign_exec_step( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, _: &Block, _: &Transaction, diff --git a/zkevm-circuits/src/evm_circuit/execution/jumpi.rs b/zkevm-circuits/src/evm_circuit/execution/jumpi.rs index 03e6fe363a..65b13de6e6 100644 --- a/zkevm-circuits/src/evm_circuit/execution/jumpi.rs +++ b/zkevm-circuits/src/evm_circuit/execution/jumpi.rs @@ -11,14 +11,15 @@ use crate::{ }, from_bytes, math_gadget::IsZeroGadget, - select, Cell, RandomLinearCombination, Word, + select, CachedRegion, Cell, RandomLinearCombination, Word, }, witness::{Block, Call, ExecStep, Transaction}, }, util::Expr, }; use eth_types::{evm_types::OpcodeId, Field, ToLittleEndian}; -use halo2_proofs::{circuit::Region, plonk::Error}; +use halo2_proofs::plonk::Error; + use std::convert::TryInto; #[derive(Clone, Debug)] @@ -84,7 +85,7 @@ impl ExecutionGadget for JumpiGadget { fn assign_exec_step( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, block: &Block, _: &Transaction, diff --git a/zkevm-circuits/src/evm_circuit/execution/logs.rs b/zkevm-circuits/src/evm_circuit/execution/logs.rs index 17106b146d..d3c218cfcb 100644 --- a/zkevm-circuits/src/evm_circuit/execution/logs.rs +++ b/zkevm-circuits/src/evm_circuit/execution/logs.rs @@ -12,7 +12,7 @@ use crate::{ }, from_bytes, memory_gadget::{MemoryAddressGadget, MemoryExpansionGadget}, - sum, Cell, Word, + sum, CachedRegion, Cell, Word, }, witness::{Block, Call, ExecStep, Transaction}, }, @@ -21,7 +21,7 @@ use crate::{ use array_init::array_init; use eth_types::Field; use eth_types::{evm_types::GasCost, evm_types::OpcodeId, ToLittleEndian, ToScalar}; -use halo2_proofs::{circuit::Region, plonk::Error}; +use halo2_proofs::plonk::Error; #[derive(Clone, Debug)] pub(crate) struct LogGadget { @@ -186,7 +186,7 @@ impl ExecutionGadget for LogGadget { fn assign_exec_step( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, block: &Block, tx: &Transaction, diff --git a/zkevm-circuits/src/evm_circuit/execution/memory.rs b/zkevm-circuits/src/evm_circuit/execution/memory.rs index dd55f1e947..d7393a13da 100644 --- a/zkevm-circuits/src/evm_circuit/execution/memory.rs +++ b/zkevm-circuits/src/evm_circuit/execution/memory.rs @@ -12,14 +12,15 @@ use crate::{ from_bytes, math_gadget::IsEqualGadget, memory_gadget::MemoryExpansionGadget, - select, MemoryAddress, Word, + select, CachedRegion, MemoryAddress, Word, }, witness::{Block, Call, ExecStep, Transaction}, }, util::Expr, }; use eth_types::{evm_types::OpcodeId, Field, ToLittleEndian}; -use halo2_proofs::{circuit::Region, plonk::Error}; +use halo2_proofs::plonk::Error; + use std::convert::TryInto; #[derive(Clone, Debug)] @@ -135,7 +136,7 @@ impl ExecutionGadget for MemoryGadget { fn assign_exec_step( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, block: &Block, _: &Transaction, diff --git a/zkevm-circuits/src/evm_circuit/execution/memory_copy.rs b/zkevm-circuits/src/evm_circuit/execution/memory_copy.rs index 0f133c8e32..b07569e9c3 100644 --- a/zkevm-circuits/src/evm_circuit/execution/memory_copy.rs +++ b/zkevm-circuits/src/evm_circuit/execution/memory_copy.rs @@ -8,7 +8,7 @@ use crate::{ constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, math_gadget::ComparisonGadget, memory_gadget::BufferReaderGadget, - Cell, + CachedRegion, Cell, }, witness::{Block, Call, ExecStep, Transaction}, }, @@ -16,7 +16,7 @@ use crate::{ }; use bus_mapping::{circuit_input_builder::CopyDetails, constants::MAX_COPY_BYTES}; use eth_types::Field; -use halo2_proofs::{circuit::Region, plonk::Error}; +use halo2_proofs::plonk::Error; /// Multi-step gadget for copying data from memory or Tx calldata to memory #[derive(Clone, Debug)] @@ -157,7 +157,7 @@ impl ExecutionGadget for CopyToMemoryGadget { fn assign_exec_step( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, block: &Block, tx: &Transaction, diff --git a/zkevm-circuits/src/evm_circuit/execution/msize.rs b/zkevm-circuits/src/evm_circuit/execution/msize.rs index f16aede9a3..ebbe8450d4 100644 --- a/zkevm-circuits/src/evm_circuit/execution/msize.rs +++ b/zkevm-circuits/src/evm_circuit/execution/msize.rs @@ -6,7 +6,7 @@ use crate::{ util::{ common_gadget::SameContextGadget, constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, - from_bytes, RandomLinearCombination, + from_bytes, CachedRegion, RandomLinearCombination, }, witness::{Block, Call, ExecStep, Transaction}, }, @@ -14,7 +14,7 @@ use crate::{ }; use bus_mapping::evm::OpcodeId; use eth_types::Field; -use halo2_proofs::{circuit::Region, plonk::Error}; +use halo2_proofs::plonk::Error; #[derive(Clone, Debug)] pub(crate) struct MsizeGadget { @@ -59,7 +59,7 @@ impl ExecutionGadget for MsizeGadget { fn assign_exec_step( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, _: &Block, _: &Transaction, diff --git a/zkevm-circuits/src/evm_circuit/execution/mul_div_mod.rs b/zkevm-circuits/src/evm_circuit/execution/mul_div_mod.rs index 9869826376..2fc1c623a5 100644 --- a/zkevm-circuits/src/evm_circuit/execution/mul_div_mod.rs +++ b/zkevm-circuits/src/evm_circuit/execution/mul_div_mod.rs @@ -6,7 +6,7 @@ use crate::{ common_gadget::SameContextGadget, constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, math_gadget::{IsZeroGadget, LtWordGadget, MulAddWordsGadget}, - select, sum, + select, sum, CachedRegion, }, witness::{Block, Call, ExecStep, Transaction}, }, @@ -14,7 +14,7 @@ use crate::{ }; use bus_mapping::evm::OpcodeId; use eth_types::{Field, U256}; -use halo2_proofs::{circuit::Region, plonk::Error}; +use halo2_proofs::plonk::Error; /// MulGadget verifies opcode MUL, DIV, and MOD. /// For MUL, verify a * b = c (mod 2^256); @@ -105,7 +105,7 @@ impl ExecutionGadget for MulDivModGadget { fn assign_exec_step( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, block: &Block, _: &Transaction, diff --git a/zkevm-circuits/src/evm_circuit/execution/number.rs b/zkevm-circuits/src/evm_circuit/execution/number.rs index 74a7d68034..3455c264aa 100644 --- a/zkevm-circuits/src/evm_circuit/execution/number.rs +++ b/zkevm-circuits/src/evm_circuit/execution/number.rs @@ -7,7 +7,7 @@ use crate::{ util::{ common_gadget::SameContextGadget, constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, - from_bytes, RandomLinearCombination, + from_bytes, CachedRegion, RandomLinearCombination, }, witness::{Block, Call, ExecStep, Transaction}, }, @@ -15,7 +15,8 @@ use crate::{ }; use bus_mapping::evm::OpcodeId; use eth_types::Field; -use halo2_proofs::{circuit::Region, plonk::Error}; +use halo2_proofs::plonk::Error; + use std::convert::TryFrom; #[derive(Clone, Debug)] @@ -61,7 +62,7 @@ impl ExecutionGadget for NumberGadget { fn assign_exec_step( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, block: &Block, _: &Transaction, diff --git a/zkevm-circuits/src/evm_circuit/execution/origin.rs b/zkevm-circuits/src/evm_circuit/execution/origin.rs index 9ae1431485..1c97fc3c16 100644 --- a/zkevm-circuits/src/evm_circuit/execution/origin.rs +++ b/zkevm-circuits/src/evm_circuit/execution/origin.rs @@ -7,7 +7,7 @@ use crate::{ util::{ common_gadget::SameContextGadget, constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, - from_bytes, Cell, RandomLinearCombination, + from_bytes, CachedRegion, Cell, RandomLinearCombination, }, witness::{Block, Call, ExecStep, Transaction}, }, @@ -15,7 +15,7 @@ use crate::{ }; use bus_mapping::evm::OpcodeId; use eth_types::{Field, ToLittleEndian}; -use halo2_proofs::{circuit::Region, plonk::Error}; +use halo2_proofs::plonk::Error; use std::convert::TryInto; #[derive(Clone, Debug)] @@ -66,7 +66,7 @@ impl ExecutionGadget for OriginGadget { fn assign_exec_step( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, block: &Block, tx: &Transaction, diff --git a/zkevm-circuits/src/evm_circuit/execution/pc.rs b/zkevm-circuits/src/evm_circuit/execution/pc.rs index 88adb60867..27b16e2e02 100644 --- a/zkevm-circuits/src/evm_circuit/execution/pc.rs +++ b/zkevm-circuits/src/evm_circuit/execution/pc.rs @@ -6,7 +6,7 @@ use crate::{ util::{ common_gadget::SameContextGadget, constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, - from_bytes, RandomLinearCombination, + from_bytes, CachedRegion, RandomLinearCombination, }, witness::{Block, Call, ExecStep, Transaction}, }, @@ -14,7 +14,7 @@ use crate::{ }; use bus_mapping::evm::OpcodeId; use eth_types::Field; -use halo2_proofs::{circuit::Region, plonk::Error}; +use halo2_proofs::plonk::Error; #[derive(Clone, Debug)] pub(crate) struct PcGadget { @@ -59,7 +59,7 @@ impl ExecutionGadget for PcGadget { fn assign_exec_step( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, _: &Block, _: &Transaction, diff --git a/zkevm-circuits/src/evm_circuit/execution/pop.rs b/zkevm-circuits/src/evm_circuit/execution/pop.rs index 2b42951b59..fe00c5e7ae 100644 --- a/zkevm-circuits/src/evm_circuit/execution/pop.rs +++ b/zkevm-circuits/src/evm_circuit/execution/pop.rs @@ -5,7 +5,7 @@ use crate::{ util::{ common_gadget::SameContextGadget, constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, - Cell, Word, + CachedRegion, Cell, Word, }, witness::{Block, Call, ExecStep, Transaction}, }, @@ -13,7 +13,7 @@ use crate::{ }; use bus_mapping::evm::OpcodeId; use eth_types::{Field, ToLittleEndian}; -use halo2_proofs::{circuit::Region, plonk::Error}; +use halo2_proofs::plonk::Error; #[derive(Clone, Debug)] pub(crate) struct PopGadget { @@ -51,7 +51,7 @@ impl ExecutionGadget for PopGadget { fn assign_exec_step( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, block: &Block, _: &Transaction, diff --git a/zkevm-circuits/src/evm_circuit/execution/push.rs b/zkevm-circuits/src/evm_circuit/execution/push.rs index d16248e8f0..85bc56bad9 100644 --- a/zkevm-circuits/src/evm_circuit/execution/push.rs +++ b/zkevm-circuits/src/evm_circuit/execution/push.rs @@ -5,7 +5,7 @@ use crate::{ util::{ common_gadget::SameContextGadget, constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, - sum, Cell, Word, + sum, CachedRegion, Cell, Word, }, witness::{Block, Call, ExecStep, Transaction}, }, @@ -13,7 +13,7 @@ use crate::{ }; use array_init::array_init; use eth_types::{evm_types::OpcodeId, Field, ToLittleEndian}; -use halo2_proofs::{circuit::Region, plonk::Error}; +use halo2_proofs::plonk::Error; #[derive(Clone, Debug)] pub(crate) struct PushGadget { @@ -114,7 +114,7 @@ impl ExecutionGadget for PushGadget { fn assign_exec_step( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, block: &Block, _: &Transaction, diff --git a/zkevm-circuits/src/evm_circuit/execution/selfbalance.rs b/zkevm-circuits/src/evm_circuit/execution/selfbalance.rs index e351a5f403..42805a46f2 100644 --- a/zkevm-circuits/src/evm_circuit/execution/selfbalance.rs +++ b/zkevm-circuits/src/evm_circuit/execution/selfbalance.rs @@ -6,7 +6,7 @@ use crate::{ util::{ common_gadget::SameContextGadget, constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, - Cell, Word, + CachedRegion, Cell, Word, }, witness::{Block, Call, ExecStep, Transaction}, }, @@ -14,7 +14,7 @@ use crate::{ }; use bus_mapping::evm::OpcodeId; use eth_types::{Field, ToLittleEndian, ToScalar}; -use halo2_proofs::{circuit::Region, plonk::Error}; +use halo2_proofs::plonk::Error; #[derive(Clone, Debug)] pub(crate) struct SelfbalanceGadget { @@ -59,7 +59,7 @@ impl ExecutionGadget for SelfbalanceGadget { fn assign_exec_step( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, block: &Block, _: &Transaction, diff --git a/zkevm-circuits/src/evm_circuit/execution/signed_comparator.rs b/zkevm-circuits/src/evm_circuit/execution/signed_comparator.rs index 41e5624b86..0be4aaab09 100644 --- a/zkevm-circuits/src/evm_circuit/execution/signed_comparator.rs +++ b/zkevm-circuits/src/evm_circuit/execution/signed_comparator.rs @@ -7,14 +7,14 @@ use crate::{ constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, from_bytes, math_gadget::{ComparisonGadget, IsEqualGadget, LtGadget}, - select, Cell, Word, + select, CachedRegion, Cell, Word, }, witness::{Block, Call, ExecStep, Transaction}, }, util::Expr, }; use eth_types::{evm_types::OpcodeId, Field, ToLittleEndian}; -use halo2_proofs::{circuit::Region, plonk::Error}; +use halo2_proofs::plonk::Error; /// Gadget that implements the ExecutionGadget trait to handle the Opcodes SLT /// and SGT. @@ -144,7 +144,7 @@ impl ExecutionGadget for SignedComparatorGadget { fn assign_exec_step( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, block: &Block, _transaction: &Transaction, diff --git a/zkevm-circuits/src/evm_circuit/execution/signextend.rs b/zkevm-circuits/src/evm_circuit/execution/signextend.rs index 2bfb7389b8..2358e96d5a 100644 --- a/zkevm-circuits/src/evm_circuit/execution/signextend.rs +++ b/zkevm-circuits/src/evm_circuit/execution/signextend.rs @@ -8,7 +8,7 @@ use crate::{ common_gadget::SameContextGadget, constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, math_gadget::{IsEqualGadget, IsZeroGadget}, - select, sum, Cell, Word, + select, sum, CachedRegion, Cell, Word, }, witness::{Block, Call, ExecStep, Transaction}, }, @@ -17,7 +17,7 @@ use crate::{ use array_init::array_init; use bus_mapping::evm::OpcodeId; use eth_types::{Field, ToLittleEndian}; -use halo2_proofs::{circuit::Region, plonk::Error}; +use halo2_proofs::plonk::Error; #[derive(Clone, Debug)] pub(crate) struct SignextendGadget { @@ -153,7 +153,7 @@ impl ExecutionGadget for SignextendGadget { fn assign_exec_step( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, block: &Block, _: &Transaction, diff --git a/zkevm-circuits/src/evm_circuit/execution/sload.rs b/zkevm-circuits/src/evm_circuit/execution/sload.rs index 9f43a78bf9..58479e2116 100644 --- a/zkevm-circuits/src/evm_circuit/execution/sload.rs +++ b/zkevm-circuits/src/evm_circuit/execution/sload.rs @@ -8,17 +8,14 @@ use crate::{ constraint_builder::{ ConstraintBuilder, ReversionInfo, StepStateTransition, Transition::Delta, }, - select, Cell, Word, + select, CachedRegion, Cell, Word, }, witness::{Block, Call, ExecStep, Transaction}, }, util::Expr, }; use eth_types::{evm_types::GasCost, Field, ToLittleEndian, ToScalar}; -use halo2_proofs::{ - circuit::Region, - plonk::{Error, Expression}, -}; +use halo2_proofs::plonk::{Error, Expression}; #[derive(Clone, Debug)] pub(crate) struct SloadGadget { @@ -94,7 +91,7 @@ impl ExecutionGadget for SloadGadget { fn assign_exec_step( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, block: &Block, tx: &Transaction, diff --git a/zkevm-circuits/src/evm_circuit/execution/sstore.rs b/zkevm-circuits/src/evm_circuit/execution/sstore.rs index f91fa767d5..864f9dbaf4 100644 --- a/zkevm-circuits/src/evm_circuit/execution/sstore.rs +++ b/zkevm-circuits/src/evm_circuit/execution/sstore.rs @@ -9,7 +9,7 @@ use crate::{ ConstraintBuilder, ReversionInfo, StepStateTransition, Transition::Delta, }, math_gadget::{IsEqualGadget, IsZeroGadget}, - not, select, Cell, Word, + not, select, CachedRegion, Cell, Word, }, witness::{Block, Call, ExecStep, Transaction}, }, @@ -17,10 +17,7 @@ use crate::{ }; use eth_types::{evm_types::GasCost, Field, ToLittleEndian, ToScalar}; -use halo2_proofs::{ - circuit::Region, - plonk::{Error, Expression}, -}; +use halo2_proofs::plonk::{Error, Expression}; #[derive(Clone, Debug)] pub(crate) struct SstoreGadget { @@ -138,7 +135,7 @@ impl ExecutionGadget for SstoreGadget { fn assign_exec_step( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, block: &Block, tx: &Transaction, @@ -293,7 +290,7 @@ impl SstoreGasGadget { #[allow(clippy::too_many_arguments)] pub(crate) fn assign( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, gas_cost: u64, value: eth_types::Word, @@ -438,7 +435,7 @@ impl SstoreTxRefundGadget { #[allow(clippy::too_many_arguments)] pub(crate) fn assign( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, tx_refund: u64, tx_refund_old: u64, diff --git a/zkevm-circuits/src/evm_circuit/execution/stop.rs b/zkevm-circuits/src/evm_circuit/execution/stop.rs index 0affc17640..642d0ef5e8 100644 --- a/zkevm-circuits/src/evm_circuit/execution/stop.rs +++ b/zkevm-circuits/src/evm_circuit/execution/stop.rs @@ -2,13 +2,13 @@ use crate::{ evm_circuit::{ execution::ExecutionGadget, step::ExecutionState, - util::{constraint_builder::ConstraintBuilder, Cell}, + util::{constraint_builder::ConstraintBuilder, CachedRegion, Cell}, witness::{Block, Call, ExecStep, Transaction}, }, util::Expr, }; use eth_types::Field; -use halo2_proofs::{circuit::Region, plonk::Error}; +use halo2_proofs::plonk::Error; #[derive(Clone, Debug)] pub(crate) struct StopGadget { @@ -32,7 +32,7 @@ impl ExecutionGadget for StopGadget { fn assign_exec_step( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, _: &Block, _: &Transaction, diff --git a/zkevm-circuits/src/evm_circuit/execution/swap.rs b/zkevm-circuits/src/evm_circuit/execution/swap.rs index 0518c7ce0c..9e9373d46f 100644 --- a/zkevm-circuits/src/evm_circuit/execution/swap.rs +++ b/zkevm-circuits/src/evm_circuit/execution/swap.rs @@ -5,14 +5,14 @@ use crate::{ util::{ common_gadget::SameContextGadget, constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, - Cell, Word, + CachedRegion, Cell, Word, }, witness::{Block, Call, ExecStep, Transaction}, }, util::Expr, }; use eth_types::{evm_types::OpcodeId, Field, ToLittleEndian}; -use halo2_proofs::{circuit::Region, plonk::Error}; +use halo2_proofs::plonk::Error; #[derive(Clone, Debug)] pub(crate) struct SwapGadget { @@ -60,7 +60,7 @@ impl ExecutionGadget for SwapGadget { fn assign_exec_step( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, block: &Block, _: &Transaction, diff --git a/zkevm-circuits/src/evm_circuit/execution/timestamp.rs b/zkevm-circuits/src/evm_circuit/execution/timestamp.rs index 0c1663102a..6141c92926 100644 --- a/zkevm-circuits/src/evm_circuit/execution/timestamp.rs +++ b/zkevm-circuits/src/evm_circuit/execution/timestamp.rs @@ -7,7 +7,7 @@ use crate::{ util::{ common_gadget::SameContextGadget, constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, - from_bytes, RandomLinearCombination, + from_bytes, CachedRegion, RandomLinearCombination, }, witness::{Block, Call, ExecStep, Transaction}, }, @@ -15,7 +15,8 @@ use crate::{ }; use bus_mapping::evm::OpcodeId; use eth_types::Field; -use halo2_proofs::{circuit::Region, plonk::Error}; +use halo2_proofs::plonk::Error; + use std::convert::TryFrom; #[derive(Clone, Debug)] @@ -59,7 +60,7 @@ impl ExecutionGadget for TimestampGadget { fn assign_exec_step( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, block: &Block, _: &Transaction, diff --git a/zkevm-circuits/src/evm_circuit/param.rs b/zkevm-circuits/src/evm_circuit/param.rs index 1dba8de849..a4496dc771 100644 --- a/zkevm-circuits/src/evm_circuit/param.rs +++ b/zkevm-circuits/src/evm_circuit/param.rs @@ -1,9 +1,21 @@ +use super::table::Table; + // Step dimension -pub(crate) const STEP_WIDTH: usize = 32; +pub(crate) const STEP_WIDTH: usize = 128; /// Step height -pub const STEP_HEIGHT: usize = 16; +pub const MAX_STEP_HEIGHT: usize = 16; pub(crate) const N_CELLS_STEP_STATE: usize = 11; +/// Lookups done per row. +pub(crate) const LOOKUP_CONFIG: &[(Table, usize)] = &[ + (Table::Fixed, 8), + (Table::Tx, 4), + (Table::Rw, 8), + (Table::Bytecode, 4), + (Table::Block, 1), + (Table::Byte, 24), +]; + /// Maximum number of bytes that an integer can fit in field without wrapping /// around. pub(crate) const MAX_N_BYTES_INTEGER: usize = 31; diff --git a/zkevm-circuits/src/evm_circuit/step.rs b/zkevm-circuits/src/evm_circuit/step.rs index c5be6fede4..637e6667f4 100644 --- a/zkevm-circuits/src/evm_circuit/step.rs +++ b/zkevm-circuits/src/evm_circuit/step.rs @@ -1,6 +1,7 @@ +use super::util::{CachedRegion, CellManager, CellType}; use crate::{ evm_circuit::{ - param::{N_CELLS_STEP_STATE, STEP_HEIGHT, STEP_WIDTH}, + param::{MAX_STEP_HEIGHT, STEP_WIDTH}, util::{Cell, RandomLinearCombination}, witness::{Block, Call, CodeSource, ExecStep, Transaction}, }, @@ -10,10 +11,8 @@ use bus_mapping::evm::OpcodeId; use eth_types::ToLittleEndian; use halo2_proofs::{ arithmetic::FieldExt, - circuit::Region, plonk::{Advice, Column, ConstraintSystem, Error, Expression}, }; -use std::collections::VecDeque; #[allow(non_camel_case_types)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] @@ -473,62 +472,37 @@ pub(crate) struct StepRow { #[derive(Clone, Debug)] pub(crate) struct Step { pub(crate) state: StepState, - pub(crate) rows: Vec>, + pub(crate) cell_manager: CellManager, } impl Step { pub(crate) fn new( meta: &mut ConstraintSystem, - qs_byte_lookup: Column, advices: [Column; STEP_WIDTH], - is_next_step: bool, + offset: usize, ) -> Self { - let num_state_cells = ExecutionState::amount() + N_CELLS_STEP_STATE; - + let mut cell_manager = CellManager::new(meta, MAX_STEP_HEIGHT, &advices, offset); let state = { - let mut cells = VecDeque::with_capacity(num_state_cells); - meta.create_gate("Query state for step", |meta| { - for idx in 0..num_state_cells { - let column_idx = idx % STEP_WIDTH; - let rotation = idx / STEP_WIDTH + if is_next_step { STEP_HEIGHT } else { 0 }; - cells.push_back(Cell::new(meta, advices[column_idx], rotation)); - } - - vec![0.expr()] - }); - StepState { - execution_state: cells.drain(..ExecutionState::amount()).collect(), - rw_counter: cells.pop_front().unwrap(), - call_id: cells.pop_front().unwrap(), - is_root: cells.pop_front().unwrap(), - is_create: cells.pop_front().unwrap(), - code_source: cells.pop_front().unwrap(), - program_counter: cells.pop_front().unwrap(), - stack_pointer: cells.pop_front().unwrap(), - gas_left: cells.pop_front().unwrap(), - memory_word_size: cells.pop_front().unwrap(), - reversible_write_counter: cells.pop_front().unwrap(), - log_id: cells.pop_front().unwrap(), + execution_state: cell_manager + .query_cells(CellType::Storage, ExecutionState::amount()), + rw_counter: cell_manager.query_cell(CellType::Storage), + call_id: cell_manager.query_cell(CellType::Storage), + is_root: cell_manager.query_cell(CellType::Storage), + is_create: cell_manager.query_cell(CellType::Storage), + code_source: cell_manager.query_cell(CellType::Storage), + program_counter: cell_manager.query_cell(CellType::Storage), + stack_pointer: cell_manager.query_cell(CellType::Storage), + gas_left: cell_manager.query_cell(CellType::Storage), + memory_word_size: cell_manager.query_cell(CellType::Storage), + reversible_write_counter: cell_manager.query_cell(CellType::Storage), + log_id: cell_manager.query_cell(CellType::Storage), } }; - - let rotation_offset = - num_state_cells / STEP_WIDTH + (num_state_cells % STEP_WIDTH != 0) as usize; - let mut rows = Vec::with_capacity(STEP_HEIGHT - rotation_offset); - meta.create_gate("Query rows for step", |meta| { - for rotation in rotation_offset..STEP_HEIGHT { - let rotation = rotation + if is_next_step { STEP_HEIGHT } else { 0 }; - rows.push(StepRow { - qs_byte_lookup: Cell::new(meta, qs_byte_lookup, rotation), - cells: advices.map(|column| Cell::new(meta, column, rotation)), - }); - } - - vec![0.expr()] - }); - - Self { state, rows } + Self { + state, + cell_manager, + } } pub(crate) fn execution_state_selector( @@ -544,7 +518,7 @@ impl Step { pub(crate) fn assign_exec_step( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, block: &Block, _: &Transaction, @@ -615,5 +589,3 @@ impl Step { Ok(()) } } - -pub(crate) type Preset = (Cell, F); diff --git a/zkevm-circuits/src/evm_circuit/table.rs b/zkevm-circuits/src/evm_circuit/table.rs index bdd75e8a98..11ad21eb45 100644 --- a/zkevm-circuits/src/evm_circuit/table.rs +++ b/zkevm-circuits/src/evm_circuit/table.rs @@ -5,25 +5,30 @@ use halo2_proofs::{ poly::Rotation, }; -pub trait LookupTable { - fn table_exprs(&self, meta: &mut VirtualCells) -> [Expression; W]; +pub trait LookupTable { + fn table_exprs(&self, meta: &mut VirtualCells) -> Vec>; } -impl LookupTable for [Column; W] { - fn table_exprs(&self, meta: &mut VirtualCells) -> [Expression; W] { - self.map(|column| meta.query_advice(column, Rotation::cur())) +impl LookupTable for [Column; W] { + fn table_exprs(&self, meta: &mut VirtualCells) -> Vec> { + self.iter() + .map(|column| meta.query_advice(*column, Rotation::cur())) + .collect() } } -impl LookupTable for [Column; W] { - fn table_exprs(&self, meta: &mut VirtualCells) -> [Expression; W] { - self.map(|column| meta.query_fixed(column, Rotation::cur())) +impl LookupTable for [Column; W] { + fn table_exprs(&self, meta: &mut VirtualCells) -> Vec> { + self.iter() + .map(|column| meta.query_fixed(*column, Rotation::cur())) + .collect() } } #[derive(Clone, Copy, Debug)] pub enum FixedTableTag { - Range5 = 1, + Zero = 0, + Range5, Range16, Range32, Range64, @@ -40,6 +45,7 @@ pub enum FixedTableTag { impl FixedTableTag { pub fn iterator() -> impl Iterator { [ + Self::Zero, Self::Range5, Self::Range16, Self::Range32, @@ -60,6 +66,7 @@ impl FixedTableTag { pub fn build(&self) -> Box> { let tag = F::from(*self as u64); match self { + Self::Zero => Box::new((0..1).map(move |_| [tag, F::zero(), F::zero(), F::zero()])), Self::Range5 => { Box::new((0..5).map(move |value| [tag, F::from(value), F::zero(), F::zero()])) } @@ -258,13 +265,33 @@ impl_expr!(BlockContextFieldTag); impl_expr!(TxLogFieldTag); impl_expr!(TxReceiptFieldTag); -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] pub(crate) enum Table { Fixed, Tx, Rw, Bytecode, Block, + Byte, +} + +impl Table { + pub(crate) fn iterator() -> impl Iterator { + [ + Self::Fixed, + Self::Tx, + Self::Rw, + Self::Bytecode, + Self::Block, + Self::Byte, + ] + .iter() + .copied() + } + + pub(crate) fn amount() -> usize { + Self::iterator().count() + } } #[derive(Clone, Debug)] @@ -329,6 +356,11 @@ pub(crate) enum Lookup { /// Value of the field. value: Expression, }, + /// Lookup to byte value. + Byte { + /// Value of the field. + value: Expression, + }, /// Conditional lookup enabled by the first element. Conditional(Expression, Box>), } @@ -345,6 +377,7 @@ impl Lookup { Self::Rw { .. } => Table::Rw, Self::Bytecode { .. } => Table::Bytecode, Self::Block { .. } => Table::Block, + Self::Byte { .. } => Table::Byte, Self::Conditional(_, lookup) => lookup.table(), } } @@ -390,6 +423,9 @@ impl Lookup { } => { vec![field_tag.clone(), number.clone(), value.clone()] } + Self::Byte { value } => { + vec![value.clone()] + } Self::Conditional(condition, lookup) => lookup .input_exprs() .into_iter() diff --git a/zkevm-circuits/src/evm_circuit/util.rs b/zkevm-circuits/src/evm_circuit/util.rs index 4c7815d8ff..c1345c43a0 100644 --- a/zkevm-circuits/src/evm_circuit/util.rs +++ b/zkevm-circuits/src/evm_circuit/util.rs @@ -1,11 +1,18 @@ -use crate::{evm_circuit::param::N_BYTES_MEMORY_ADDRESS, util::Expr}; +use crate::{ + evm_circuit::{ + param::{LOOKUP_CONFIG, N_BYTES_MEMORY_ADDRESS}, + table::Table, + }, + util::Expr, +}; use eth_types::U256; use halo2_proofs::{ arithmetic::FieldExt, circuit::{AssignedCell, Region}, - plonk::{Advice, Column, Error, Expression, VirtualCells}, + plonk::{Advice, Assigned, Column, ConstraintSystem, Error, Expression, VirtualCells}, poly::Rotation, }; +use std::collections::BTreeMap; pub(crate) mod common_gadget; pub(crate) mod constraint_builder; @@ -32,7 +39,7 @@ impl Cell { pub(crate) fn assign( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, value: Option, ) -> Result, Error> { @@ -62,6 +69,231 @@ impl Expr for &Cell { } } +pub struct CachedRegion<'r, 'b, F: FieldExt> { + region: &'r mut Region<'b, F>, + advice: Vec>, + power_of_randomness: [F; 31], + width_start: usize, + height_start: usize, +} + +impl<'r, 'b, F: FieldExt> CachedRegion<'r, 'b, F> { + /// New cached region + pub(crate) fn new( + region: &'r mut Region<'b, F>, + power_of_randomness: [F; 31], + width: usize, + height: usize, + width_start: usize, + height_start: usize, + ) -> Self { + Self { + region, + advice: vec![vec![F::zero(); height]; width], + power_of_randomness, + width_start, + height_start, + } + } + + /// Assign an advice column value (witness). + pub fn assign_advice<'v, V, VR, A, AR>( + &'v mut self, + annotation: A, + column: Column, + offset: usize, + to: V, + ) -> Result, Error> + where + V: FnMut() -> Result + 'v, + for<'vr> Assigned: From<&'vr VR>, + A: Fn() -> AR, + AR: Into, + { + // Actually set the value + let res = self.region.assign_advice(annotation, column, offset, to); + // Cache the value + if let Result::Ok(cell) = &res { + let call_value = cell.value_field(); + if let Some(value) = call_value { + self.advice[column.index() - self.width_start][offset - self.height_start] = + value.evaluate(); + } + } + res + } + + pub fn get_fixed(&self, _row_index: usize, _column_index: usize, _rotation: Rotation) -> F { + unimplemented!("fixed column"); + } + + pub fn get_advice(&self, row_index: usize, column_index: usize, rotation: Rotation) -> F { + self.advice[column_index - self.width_start] + [(((row_index - self.height_start) as i32) + rotation.0) as usize] + } + + pub fn get_instance(&self, _row_index: usize, column_index: usize, _rotation: Rotation) -> F { + self.power_of_randomness[column_index] + } +} + +#[derive(Debug, Clone)] +pub struct StoredExpression { + name: String, + cell: Cell, + cell_type: CellType, + expr: Expression, + expr_id: String, +} + +impl StoredExpression { + pub fn assign( + &self, + region: &mut CachedRegion<'_, '_, F>, + offset: usize, + ) -> Result, Error> { + let value = self.expr.evaluate( + &|scalar| scalar, + &|_| unimplemented!("selector column"), + &|_, column_index, rotation| region.get_fixed(offset, column_index, rotation), + &|_, column_index, rotation| region.get_advice(offset, column_index, rotation), + &|_, column_index, rotation| region.get_instance(offset, column_index, rotation), + &|a| -a, + &|a, b| a + b, + &|a, b| a * b, + &|a, scalar| a * scalar, + ); + self.cell.assign(region, offset, Some(value)) + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub(crate) enum CellType { + Storage, + Lookup(Table), +} + +#[derive(Clone, Debug)] +pub(crate) struct CellColumn { + pub(crate) index: usize, + pub(crate) cell_type: CellType, + pub(crate) height: usize, + pub(crate) expr: Expression, +} + +impl Expr for CellColumn { + fn expr(&self) -> Expression { + self.expr.clone() + } +} + +#[derive(Clone, Debug)] +pub(crate) struct CellManager { + width: usize, + height: usize, + cells: Vec>, + columns: Vec>, +} + +impl CellManager { + pub(crate) fn new( + meta: &mut ConstraintSystem, + height: usize, + advices: &[Column], + height_offset: usize, + ) -> Self { + // Setup the columns and query the cells + let width = advices.len(); + let mut cells = Vec::with_capacity(height * width); + let mut columns = Vec::with_capacity(height); + meta.create_gate("Query rows for step", |meta| { + for c in 0..width { + for r in 0..height { + cells.push(Cell::new(meta, advices[c], height_offset + r)); + } + columns.push(CellColumn { + index: c, + cell_type: CellType::Storage, + height: 0, + expr: cells[c * height].expr(), + }); + } + vec![0.expr()] + }); + + // Mark columns used for lookups + let mut column_idx = 0; + for &(table, count) in LOOKUP_CONFIG { + for _ in 0usize..count { + columns[column_idx].cell_type = CellType::Lookup(table); + column_idx += 1; + } + } + + Self { + width, + height, + cells, + columns, + } + } + + pub(crate) fn query_cells(&mut self, cell_type: CellType, count: usize) -> Vec> { + let mut cells = Vec::with_capacity(count); + while cells.len() < count { + let column_idx = self.next_column(cell_type); + let column = &mut self.columns[column_idx]; + cells.push(self.cells[column_idx * self.height + column.height].clone()); + column.height += 1; + } + cells + } + + pub(crate) fn query_cell(&mut self, cell_type: CellType) -> Cell { + self.query_cells(cell_type, 1)[0].clone() + } + + fn next_column(&self, cell_type: CellType) -> usize { + let mut best_index: Option = None; + let mut best_height = self.height; + for column in self.columns.iter() { + if column.cell_type == cell_type && column.height < best_height { + best_index = Some(column.index); + best_height = column.height; + } + } + match best_index { + Some(index) => index, + None => unreachable!(format!("not enough cells for query: {:?}", cell_type)), + } + } + + pub(crate) fn get_height(&self) -> usize { + self.columns + .iter() + .map(|column| column.height) + .max() + .unwrap() + } + + pub(crate) fn get_stats(&self) -> BTreeMap { + let mut data = BTreeMap::new(); + for column in self.columns.iter() { + let (mut count, mut height, mut num_cells) = + data.get(&column.cell_type).unwrap_or(&(0, 0, 0)); + count += 1; + height = height.max(column.height); + num_cells += column.height; + data.insert(column.cell_type, (count, height, num_cells)); + } + data + } + + pub(crate) fn columns(&self) -> &[CellColumn] { + &self.columns + } +} + #[derive(Clone, Debug)] pub(crate) struct RandomLinearCombination { // random linear combination expression of cells @@ -74,22 +306,14 @@ impl RandomLinearCombination { const N_BYTES: usize = N; pub(crate) fn random_linear_combine(bytes: [u8; N], randomness: F) -> F { - bytes.iter().rev().fold(F::zero(), |acc, byte| { - acc * randomness + F::from(*byte as u64) - }) + rlc::value(&bytes, randomness) } pub(crate) fn random_linear_combine_expr( bytes: [Expression; N], power_of_randomness: &[Expression], ) -> Expression { - debug_assert!(bytes.len() <= power_of_randomness.len() + 1); - - let mut rlc = bytes[0].clone(); - for (byte, randomness) in bytes[1..].iter().zip(power_of_randomness.iter()) { - rlc = rlc + byte.clone() * randomness.clone(); - } - rlc + rlc::expr(&bytes, power_of_randomness) } pub(crate) fn new(cells: [Cell; N], power_of_randomness: &[Expression]) -> Self { @@ -104,7 +328,7 @@ impl RandomLinearCombination { pub(crate) fn assign( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, bytes: Option<[u8; N]>, ) -> Result>, Error> { @@ -264,6 +488,32 @@ pub(crate) mod from_bytes { } } +/// Returns the random linear combination of the inputs. +/// Encoding is done as follows: v_0 * R^0 + v_1 * R^1 + ... +pub(crate) mod rlc { + use crate::util::Expr; + use halo2_proofs::{arithmetic::FieldExt, plonk::Expression}; + + pub(crate) fn expr>( + expressions: &[E], + power_of_randomness: &[E], + ) -> Expression { + debug_assert!(expressions.len() <= power_of_randomness.len() + 1); + + let mut rlc = expressions[0].expr(); + for (expression, randomness) in expressions[1..].iter().zip(power_of_randomness.iter()) { + rlc = rlc + expression.expr() * randomness.expr(); + } + rlc + } + + pub(crate) fn value(values: &[u8], randomness: F) -> F { + values.iter().rev().fold(F::zero(), |acc, value| { + acc * randomness + F::from(*value as u64) + }) + } +} + /// Returns 2**by as FieldExt pub(crate) fn pow_of_two(by: usize) -> F { F::from(2).pow(&[by as u64, 0, 0, 0]) diff --git a/zkevm-circuits/src/evm_circuit/util/common_gadget.rs b/zkevm-circuits/src/evm_circuit/util/common_gadget.rs index 68b839ed37..d8d33a7bda 100644 --- a/zkevm-circuits/src/evm_circuit/util/common_gadget.rs +++ b/zkevm-circuits/src/evm_circuit/util/common_gadget.rs @@ -1,3 +1,4 @@ +use super::CachedRegion; use crate::{ evm_circuit::{ param::N_BYTES_GAS, @@ -12,10 +13,7 @@ use crate::{ util::Expr, }; use eth_types::{Field, U256}; -use halo2_proofs::{ - circuit::Region, - plonk::{Error, Expression}, -}; +use halo2_proofs::plonk::{Error, Expression}; use std::convert::TryInto; /// Construction of execution state that stays in the same call context, which @@ -60,7 +58,7 @@ impl SameContextGadget { pub(crate) fn assign_exec_step( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, step: &ExecStep, ) -> Result<(), Error> { @@ -142,7 +140,7 @@ impl pub(crate) fn assign( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, value_prev: U256, updates: Vec, @@ -191,7 +189,7 @@ impl TransferWithGasFeeGadget { pub(crate) fn assign( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, (sender_balance, sender_balance_prev): (U256, U256), (receiver_balance, receiver_balance_prev): (U256, U256), @@ -248,7 +246,7 @@ impl TransferGadget { pub(crate) fn assign( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, (sender_balance, sender_balance_prev): (U256, U256), (receiver_balance, receiver_balance_prev): (U256, U256), diff --git a/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs b/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs index 48158a8efa..e675389578 100644 --- a/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs +++ b/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs @@ -1,10 +1,10 @@ use crate::{ evm_circuit::{ param::STACK_CAPACITY, - step::{ExecutionState, Preset, Step}, + step::{ExecutionState, Step}, table::{ AccountFieldTag, BytecodeFieldTag, CallContextFieldTag, FixedTableTag, Lookup, - RwTableTag, TxContextFieldTag, TxLogFieldTag, TxReceiptFieldTag, + RwTableTag, Table, TxContextFieldTag, TxLogFieldTag, TxReceiptFieldTag, }, util::{Cell, RandomLinearCombination, Word}, }, @@ -12,7 +12,6 @@ use crate::{ }; use halo2_proofs::{ arithmetic::FieldExt, - circuit::Region, plonk::{ Error, Expression::{self, Constant}, @@ -20,14 +19,14 @@ use halo2_proofs::{ }; use std::convert::TryInto; +use super::{rlc, CachedRegion, CellType, StoredExpression}; + // Max degree allowed in all expressions passing through the ConstraintBuilder. -// It aims to cap `extended_k` to 4, which allows constraint degree to 2^4+1, -// but each ExecutionGadget has implicit selector degree 2, so here it only -// allows 2^4+1-2 = 15. -const MAX_DEGREE: usize = 15; -// Implicit degree added to input expressions of lookups. It assumes blind -// factors have been disabled, and table expressions with degree 1. -const LOOKUP_DEGREE: usize = 2; +// It aims to cap `extended_k` to 2, which allows constraint degree to 2^2+1, +// but each ExecutionGadget has implicit selector degree 3, so here it only +// allows 2^2+1-3 = 2. +const MAX_DEGREE: usize = 5; +const IMPLICIT_DEGREE: usize = 3; #[derive(Clone, Debug, Default)] struct StepRowUsage { @@ -127,7 +126,7 @@ impl ReversionInfo { pub(crate) fn assign( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, rw_counter_end_of_reversion: usize, is_persistent: bool, @@ -145,8 +144,8 @@ impl ReversionInfo { #[derive(Default)] pub struct BaseConstraintBuilder { - pub constraints: Vec<(&'static str, Expression)>, - pub max_degree: usize, + constraints: Vec<(&'static str, Expression)>, + max_degree: usize, condition: Option>, } @@ -241,46 +240,44 @@ impl BaseConstraintBuilder { } pub(crate) struct ConstraintBuilder<'a, F> { - pub(crate) curr: &'a Step, - pub(crate) next: &'a Step, + pub max_degree: usize, + pub(crate) curr: Step, + pub(crate) next: Step, power_of_randomness: &'a [Expression; 31], execution_state: ExecutionState, - cb: BaseConstraintBuilder, + constraints: Vec<(&'static str, Expression)>, constraints_first_step: Vec<(&'static str, Expression)>, - lookups: Vec<(&'static str, Lookup)>, - curr_row_usages: Vec, - next_row_usages: Vec, rw_counter_offset: Expression, program_counter_offset: usize, stack_pointer_offset: i32, log_id_offset: usize, in_next_step: bool, condition: Option>, + stored_expressions: Vec>, } impl<'a, F: FieldExt> ConstraintBuilder<'a, F> { pub(crate) fn new( - curr: &'a Step, - next: &'a Step, + curr: Step, + next: Step, power_of_randomness: &'a [Expression; 31], execution_state: ExecutionState, ) -> Self { Self { + max_degree: MAX_DEGREE, curr, next, power_of_randomness, execution_state, - cb: BaseConstraintBuilder::new(MAX_DEGREE), + constraints: Vec::new(), constraints_first_step: Vec::new(), - lookups: Vec::new(), - curr_row_usages: vec![StepRowUsage::default(); curr.rows.len()], - next_row_usages: vec![StepRowUsage::default(); next.rows.len()], rw_counter_offset: 0.expr(), program_counter_offset: 0, stack_pointer_offset: 0, log_id_offset: 0, in_next_step: false, condition: None, + stored_expressions: Vec::new(), } } @@ -290,36 +287,12 @@ impl<'a, F: FieldExt> ConstraintBuilder<'a, F> { ) -> ( Vec<(&'static str, Expression)>, Vec<(&'static str, Expression)>, - Vec<(&'static str, Lookup)>, - Vec>, + Vec>, + usize, ) { - let mut constraints = self.cb.constraints; - let mut presets = Vec::new(); - - for (row, usage) in self.curr.rows.iter().zip(self.curr_row_usages.iter()) { - if usage.is_byte_lookup_enabled { - constraints.push(("Enable byte lookup", row.qs_byte_lookup.expr() - 1.expr())); - } - - presets.extend( - row.cells[usage.next_idx..] - .iter() - .map(|cell| (cell.clone(), F::zero())), - ); - presets.push(( - row.qs_byte_lookup.clone(), - if usage.is_byte_lookup_enabled { - F::one() - } else { - F::zero() - }, - )); - } - let execution_state_selector = self.curr.execution_state_selector([self.execution_state]); - ( - constraints + self.constraints .into_iter() .map(|(name, constraint)| (name, execution_state_selector.clone() * constraint)) .collect(), @@ -327,11 +300,8 @@ impl<'a, F: FieldExt> ConstraintBuilder<'a, F> { .into_iter() .map(|(name, constraint)| (name, execution_state_selector.clone() * constraint)) .collect(), - self.lookups - .into_iter() - .map(|(name, lookup)| (name, lookup.conditional(execution_state_selector.clone()))) - .collect(), - presets, + self.stored_expressions, + self.curr.cell_manager.get_height(), ) } @@ -368,19 +338,13 @@ impl<'a, F: FieldExt> ConstraintBuilder<'a, F> { } pub(crate) fn query_bool(&mut self) -> Cell { - let [cell] = self.query_cells::<1>(false); + let cell = self.query_cell(); self.require_boolean("Constrain cell to be a bool", cell.expr()); cell } pub(crate) fn query_byte(&mut self) -> Cell { - let [cell] = self.query_cells::<1>(true); - cell - } - - pub(crate) fn query_cell(&mut self) -> Cell { - let [cell] = self.query_cells::<1>(false); - cell + self.query_cell_with_type(CellType::Lookup(Table::Byte)) } pub(crate) fn query_word(&mut self) -> Word { @@ -392,52 +356,35 @@ impl<'a, F: FieldExt> ConstraintBuilder<'a, F> { } pub(crate) fn query_bytes(&mut self) -> [Cell; N] { - self.query_cells::(true) + self.query_bytes_dyn(N).try_into().unwrap() } - fn query_cells(&mut self, is_byte: bool) -> [Cell; N] { - let mut cells = Vec::with_capacity(N); - let rows = if self.in_next_step { - &self.next.rows - } else { - &self.curr.rows - }; - let row_usages = if self.in_next_step { - &mut self.next_row_usages - } else { - &mut self.curr_row_usages - }; - - // Iterate rows to find cell that matches the is_byte requirement. - for (row, usage) in rows.iter().zip(row_usages.iter_mut()) { - // If this row doesn't match the is_byte requirement and is already - // used, skip this row. - if usage.is_byte_lookup_enabled != is_byte && usage.next_idx > 0 { - continue; - } + pub(crate) fn query_bytes_dyn(&mut self, count: usize) -> Vec> { + self.query_cells(CellType::Lookup(Table::Byte), count) + } - // Enable the byte range lookup for this row if queried cells are - // required to be bytes. - if usage.next_idx == 0 && is_byte { - usage.is_byte_lookup_enabled = true; - } + pub(crate) fn query_cell(&mut self) -> Cell { + self.query_cell_with_type(CellType::Storage) + } - let n = row.cells.len().min(usage.next_idx + N - cells.len()); - cells.extend(row.cells[usage.next_idx..n].iter().cloned()); - usage.next_idx = n; + pub(crate) fn query_cell_with_type(&mut self, cell_type: CellType) -> Cell { + self.query_cells(cell_type, 1).first().unwrap().clone() + } - if cells.len() == N { - return cells.try_into().unwrap(); - } + fn query_cells(&mut self, cell_type: CellType, count: usize) -> Vec> { + if self.in_next_step { + &mut self.next + } else { + &mut self.curr } - - unreachable!("not enough cells for query") + .cell_manager + .query_cells(cell_type, count) } // Common pub(crate) fn require_zero(&mut self, name: &'static str, constraint: Expression) { - self.cb.require_zero(name, constraint); + self.add_constraint(name, constraint); } pub(crate) fn require_equal( @@ -446,11 +393,11 @@ impl<'a, F: FieldExt> ConstraintBuilder<'a, F> { lhs: Expression, rhs: Expression, ) { - self.cb.require_equal(name, lhs, rhs); + self.add_constraint(name, lhs - rhs); } pub(crate) fn require_boolean(&mut self, name: &'static str, value: Expression) { - self.cb.require_boolean(name, value); + self.add_constraint(name, value.clone() * (1.expr() - value)); } pub(crate) fn require_in_set( @@ -459,7 +406,11 @@ impl<'a, F: FieldExt> ConstraintBuilder<'a, F> { value: Expression, set: Vec>, ) { - self.cb.require_in_set(name, value, set); + self.add_constraint( + name, + set.iter() + .fold(1.expr(), |acc, item| acc * (value.clone() - item.clone())), + ); } pub(crate) fn require_next_state(&mut self, execution_state: ExecutionState) { @@ -704,7 +655,7 @@ impl<'a, F: FieldExt> ConstraintBuilder<'a, F> { // Manually constant folding is used here, since halo2 cannot do this // automatically. Better error message will be printed during circuit // debugging. - self.rw_counter_offset = match &self.cb.condition { + self.rw_counter_offset = match &self.condition { None => { if let Constant(v) = self.rw_counter_offset { Constant(v + F::from(1u64)) @@ -1150,14 +1101,15 @@ impl<'a, F: FieldExt> ConstraintBuilder<'a, F> { // Validation pub(crate) fn validate_degree(&self, degree: usize, name: &'static str) { - // We need to subtract 2 from MAX_DEGREE because all expressions will be - // multiplied by state selector and q_step/q_step_first selector. + // We need to subtract IMPLICIT_DEGREE from MAX_DEGREE because all expressions + // will be multiplied by state selector and q_step/q_step_first + // selector. debug_assert!( - degree <= MAX_DEGREE - 2, + degree <= MAX_DEGREE - IMPLICIT_DEGREE, "Expression {} degree too high: {} > {}", name, degree, - MAX_DEGREE - 2, + MAX_DEGREE - IMPLICIT_DEGREE, ); } @@ -1169,12 +1121,12 @@ impl<'a, F: FieldExt> ConstraintBuilder<'a, F> { constraint: impl FnOnce(&mut Self) -> R, ) -> R { debug_assert!( - self.cb.condition.is_none(), + self.condition.is_none(), "Nested condition is not supported" ); - self.cb.condition = Some(condition); + self.condition = Some(condition); let ret = constraint(self); - self.cb.condition = None; + self.condition = None; ret } @@ -1205,11 +1157,21 @@ impl<'a, F: FieldExt> ConstraintBuilder<'a, F> { } pub(crate) fn add_constraints(&mut self, constraints: Vec<(&'static str, Expression)>) { - self.cb.add_constraints(constraints); + for (name, constraint) in constraints { + self.add_constraint(name, constraint); + } } pub(crate) fn add_constraint(&mut self, name: &'static str, constraint: Expression) { - self.cb.add_constraint(name, constraint); + let constraint = match &self.condition { + Some(condition) => condition.clone() * constraint, + None => constraint, + }; + + let constraint = self.split_expression(name, constraint, MAX_DEGREE - IMPLICIT_DEGREE); + + self.validate_degree(constraint.degree(), name); + self.constraints.push((name, constraint)); } pub(crate) fn add_constraint_first_step( @@ -1217,21 +1179,123 @@ impl<'a, F: FieldExt> ConstraintBuilder<'a, F> { name: &'static str, constraint: Expression, ) { - let constraint = match &self.cb.condition { + let constraint = match &self.condition { Some(condition) => condition.clone() * constraint, None => constraint, }; - // Add 1 more degree due to the selector - self.validate_degree(constraint.degree() + 1, name); + self.validate_degree(constraint.degree(), name); self.constraints_first_step.push((name, constraint)); } pub(crate) fn add_lookup(&mut self, name: &'static str, lookup: Lookup) { - let lookup = match &self.cb.condition { + let lookup = match &self.condition { Some(condition) => lookup.conditional(condition.clone()), None => lookup, }; - self.validate_degree(lookup.degree() + LOOKUP_DEGREE, name); - self.lookups.push((name, lookup)); + + let compressed_expr = self.split_expression( + "Lookup compression", + rlc::expr(&lookup.input_exprs(), self.power_of_randomness), + MAX_DEGREE - IMPLICIT_DEGREE, + ); + self.store_expression(name, compressed_expr, CellType::Lookup(lookup.table())); + } + + pub(crate) fn store_expression( + &mut self, + name: &'static str, + expr: Expression, + cell_type: CellType, + ) -> Expression { + // Check if we already stored the expression somewhere + let stored_expression = self.find_stored_expression(expr.clone(), cell_type); + match stored_expression { + Some(stored_expression) => { + debug_assert!( + !matches!(cell_type, CellType::Lookup(_)), + "The same lookup is done multiple times", + ); + stored_expression.cell.expr() + } + None => { + // Even if we're building expressions for the next step, + // these intermediate values need to be stored in the current step. + let in_next_step = self.in_next_step; + self.in_next_step = false; + let cell = self.query_cell_with_type(cell_type); + self.in_next_step = in_next_step; + + // Require the stored value to equal the value of the expression + let name = format!("{} (stored expression)", name); + self.constraints.push(( + Box::leak(name.clone().into_boxed_str()), + cell.expr() - expr.clone(), + )); + + self.stored_expressions.push(StoredExpression { + name, + cell: cell.clone(), + cell_type, + expr_id: expr.identifier(), + expr, + }); + cell.expr() + } + } + } + + pub(crate) fn find_stored_expression( + &self, + expr: Expression, + cell_type: CellType, + ) -> Option<&StoredExpression> { + let expr_id = expr.identifier(); + self.stored_expressions + .iter() + .find(|&e| e.cell_type == cell_type && e.expr_id == expr_id) + } + + fn split_expression( + &mut self, + name: &'static str, + expr: Expression, + max_degree: usize, + ) -> Expression { + if expr.degree() > max_degree { + match expr { + Expression::Negated(poly) => { + Expression::Negated(Box::new(self.split_expression(name, *poly, max_degree))) + } + Expression::Scaled(poly, v) => { + Expression::Scaled(Box::new(self.split_expression(name, *poly, max_degree)), v) + } + Expression::Sum(a, b) => { + let a = self.split_expression(name, *a, max_degree); + let b = self.split_expression(name, *b, max_degree); + a + b + } + Expression::Product(a, b) => { + let (mut a, mut b) = (*a, *b); + while a.degree() + b.degree() > max_degree { + let mut split = |expr: Expression| { + if expr.degree() > max_degree { + self.split_expression(name, expr, max_degree) + } else { + self.store_expression(name, expr, CellType::Storage) + } + }; + if a.degree() >= b.degree() { + a = split(a); + } else { + b = split(b); + } + } + a * b + } + _ => expr.clone(), + } + } else { + expr.clone() + } } } diff --git a/zkevm-circuits/src/evm_circuit/util/math_gadget.rs b/zkevm-circuits/src/evm_circuit/util/math_gadget.rs index 2aeab94a85..8c1136c593 100644 --- a/zkevm-circuits/src/evm_circuit/util/math_gadget.rs +++ b/zkevm-circuits/src/evm_circuit/util/math_gadget.rs @@ -1,3 +1,4 @@ +use super::CachedRegion; use crate::{ evm_circuit::util::{ self, constraint_builder::ConstraintBuilder, from_bytes, pow_of_two, pow_of_two_expr, @@ -6,10 +7,7 @@ use crate::{ util::Expr, }; use eth_types::{Field, ToLittleEndian, ToScalar, Word}; -use halo2_proofs::{ - circuit::Region, - plonk::{Error, Expression}, -}; +use halo2_proofs::plonk::{Error, Expression}; use std::convert::TryFrom; /// Returns `1` when `value == 0`, and returns `0` otherwise. @@ -43,7 +41,7 @@ impl IsZeroGadget { pub(crate) fn assign( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, value: F, ) -> Result { @@ -80,7 +78,7 @@ impl IsEqualGadget { pub(crate) fn assign( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, lhs: F, rhs: F, @@ -126,7 +124,7 @@ impl BatchedIsZeroGadget { pub(crate) fn assign( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, values: [F; N], ) -> Result { @@ -221,7 +219,7 @@ impl pub(crate) fn assign( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, addends: [Word; N_ADDENDS], sum: Word, @@ -314,7 +312,7 @@ impl MulWordByU64Gadget { pub(crate) fn assign( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, multiplicand: Word, multiplier: u64, @@ -370,7 +368,7 @@ impl RangeCheckGadget { pub(crate) fn assign( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, value: F, ) -> Result<(), Error> { @@ -425,7 +423,7 @@ impl LtGadget { pub(crate) fn assign( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, lhs: F, rhs: F, @@ -487,7 +485,7 @@ impl LtWordGadget { pub(crate) fn assign( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, lhs: Word, rhs: Word, @@ -539,7 +537,7 @@ impl ComparisonGadget { pub(crate) fn assign( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, lhs: F, rhs: F, @@ -591,7 +589,7 @@ impl PairSelectGadget { pub(crate) fn assign( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, value: F, a: F, @@ -659,7 +657,7 @@ impl ConstantDivisionGadget { pub(crate) fn assign( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, numerator: u128, ) -> Result<(u128, u128), Error> { @@ -712,7 +710,7 @@ impl MinMaxGadget { pub(crate) fn assign( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, lhs: F, rhs: F, @@ -853,7 +851,7 @@ impl MulAddWordsGadget { pub(crate) fn assign( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, words: [Word; 4], ) -> Result<(), Error> { diff --git a/zkevm-circuits/src/evm_circuit/util/memory_gadget.rs b/zkevm-circuits/src/evm_circuit/util/memory_gadget.rs index c85edaa3d3..c6a5cb6148 100644 --- a/zkevm-circuits/src/evm_circuit/util/memory_gadget.rs +++ b/zkevm-circuits/src/evm_circuit/util/memory_gadget.rs @@ -1,3 +1,4 @@ +use super::CachedRegion; use crate::{ evm_circuit::{ param::{N_BYTES_GAS, N_BYTES_MEMORY_ADDRESS, N_BYTES_MEMORY_WORD_SIZE}, @@ -12,10 +13,7 @@ use crate::{ }; use array_init::array_init; use eth_types::{evm_types::GasCost, Field, ToLittleEndian, U256}; -use halo2_proofs::{ - circuit::Region, - plonk::{Error, Expression}, -}; +use halo2_proofs::plonk::{Error, Expression}; use std::convert::TryInto; /// Decodes the usable part of an address stored in a Word @@ -95,7 +93,7 @@ impl MemoryAddressGadget { pub(crate) fn assign( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, memory_offset: U256, memory_length: U256, @@ -176,7 +174,7 @@ impl MemoryWordSizeGadget { pub(crate) fn assign( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, address: u64, ) -> Result { @@ -280,7 +278,7 @@ impl pub(crate) fn assign( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, curr_memory_word_size: u64, addresses: [u64; N], @@ -377,7 +375,7 @@ impl MemoryCopierGasGadget { pub(crate) fn assign( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, num_bytes: u64, memory_expansion_gas_cost: u64, @@ -490,7 +488,7 @@ impl pub(crate) fn assign( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, addr_start: u64, addr_end: u64, diff --git a/zkevm-circuits/src/evm_circuit/witness.rs b/zkevm-circuits/src/evm_circuit/witness.rs index a4a4a5ec7f..b73f2d665f 100644 --- a/zkevm-circuits/src/evm_circuit/witness.rs +++ b/zkevm-circuits/src/evm_circuit/witness.rs @@ -19,6 +19,7 @@ use eth_types::evm_types::OpcodeId; use eth_types::{Address, Field, ToLittleEndian, ToScalar, ToWord, Word}; use halo2_proofs::arithmetic::{BaseExt, FieldExt}; use halo2_proofs::pairing::bn256::Fr as Fp; +use itertools::Itertools; use sha3::{Digest, Keccak256}; use std::{collections::HashMap, convert::TryInto, iter}; @@ -1378,7 +1379,10 @@ pub fn block_convert( .flat_map(|tx| { tx.calls() .iter() - .map(|call| Bytecode::new(code_db.0.get(&call.code_hash).unwrap().to_vec())) + .map(|call| call.code_hash) + .unique() + .into_iter() + .map(|code_hash| Bytecode::new(code_db.0.get(&code_hash).unwrap().to_vec())) }) .collect(), } diff --git a/zkevm-circuits/src/rw_table.rs b/zkevm-circuits/src/rw_table.rs index 60eb589d26..c08c05dce3 100644 --- a/zkevm-circuits/src/rw_table.rs +++ b/zkevm-circuits/src/rw_table.rs @@ -24,9 +24,9 @@ pub struct RwTable { pub aux2: Column, } -impl LookupTable for RwTable { - fn table_exprs(&self, meta: &mut VirtualCells) -> [Expression; 11] { - [ +impl LookupTable for RwTable { + fn table_exprs(&self, meta: &mut VirtualCells) -> Vec> { + vec![ meta.query_advice(self.rw_counter, Rotation::cur()), meta.query_advice(self.is_write, Rotation::cur()), meta.query_advice(self.tag, Rotation::cur()), diff --git a/zkevm-circuits/src/test_util.rs b/zkevm-circuits/src/test_util.rs index c1ad0639d0..cbcd2a9852 100644 --- a/zkevm-circuits/src/test_util.rs +++ b/zkevm-circuits/src/test_util.rs @@ -23,6 +23,7 @@ pub fn get_fixed_table(conf: FixedTableConfig) -> Vec { match conf { FixedTableConfig::Incomplete => { vec![ + FixedTableTag::Zero, FixedTableTag::Range5, FixedTableTag::Range16, FixedTableTag::Range32,