diff --git a/integration-tests/src/integration_test_circuits.rs b/integration-tests/src/integration_test_circuits.rs index 2faa9a49b4..58fe829064 100644 --- a/integration-tests/src/integration_test_circuits.rs +++ b/integration-tests/src/integration_test_circuits.rs @@ -25,7 +25,7 @@ use std::collections::HashMap; use std::sync::Mutex; use zkevm_circuits::bytecode_circuit::bytecode_unroller::BytecodeCircuit; use zkevm_circuits::copy_circuit::CopyCircuit; -use zkevm_circuits::evm_circuit::test::{get_test_degree, get_test_instance}; +use zkevm_circuits::evm_circuit::test::get_test_degree; use zkevm_circuits::evm_circuit::{test::get_test_cicuit_from_block, witness::block_convert}; use zkevm_circuits::state_circuit::StateCircuit; use zkevm_circuits::super_circuit::SuperCircuit; @@ -245,13 +245,12 @@ pub async fn test_evm_circuit_block(block_num: u64, actual: bool) { let block = block_convert(&builder.block, &builder.code_db).unwrap(); let degree = get_test_degree(&block); - let instance = get_test_instance(&block); let circuit = get_test_cicuit_from_block(block); if actual { - test_actual(degree, circuit, instance, None); + test_actual(degree, circuit, vec![], None); } else { - test_mock(degree, &circuit, instance); + test_mock(degree, &circuit, vec![]); } } diff --git a/zkevm-circuits/src/copy_circuit.rs b/zkevm-circuits/src/copy_circuit.rs index 0e5cab12cf..279d50c821 100644 --- a/zkevm-circuits/src/copy_circuit.rs +++ b/zkevm-circuits/src/copy_circuit.rs @@ -308,7 +308,7 @@ impl SubCircuitConfig for CopyCircuitConfig { cb.require_equal( "rows[2].value == rows[0].value * r + rows[1].value", meta.query_advice(value, Rotation(2)), - meta.query_advice(value, Rotation::cur()) * challenges.evm_word() + meta.query_advice(value, Rotation::cur()) * challenges.keccak_input() + meta.query_advice(value, Rotation::next()), ); diff --git a/zkevm-circuits/src/evm_circuit.rs b/zkevm-circuits/src/evm_circuit.rs index 4c6722f925..fc7e147739 100644 --- a/zkevm-circuits/src/evm_circuit.rs +++ b/zkevm-circuits/src/evm_circuit.rs @@ -42,8 +42,8 @@ pub struct EvmCircuitConfig { /// Circuit configuration arguments pub struct EvmCircuitConfigArgs { - /// Power of randomness - pub power_of_randomness: [Expression; 31], + /// Challenge + pub challenges: Challenges>, /// TxTable pub tx_table: TxTable, /// RwTable @@ -68,7 +68,7 @@ impl SubCircuitConfig for EvmCircuitConfig { fn new( meta: &mut ConstraintSystem, Self::ConfigArgs { - power_of_randomness, + challenges, tx_table, rw_table, bytecode_table, @@ -82,7 +82,7 @@ impl SubCircuitConfig for EvmCircuitConfig { let byte_table = [(); 1].map(|_| meta.fixed_column()); let execution = Box::new(ExecutionConfig::configure( meta, - power_of_randomness, + challenges, &fixed_table, &byte_table, &tx_table, @@ -233,14 +233,14 @@ impl SubCircuit for EvmCircuit { fn synthesize_sub( &self, config: &Self::Config, - _challenges: &Challenges>, + challenges: &Challenges>, layouter: &mut impl Layouter, ) -> Result<(), Error> { let block = self.block.as_ref().unwrap(); config.load_fixed_table(layouter, self.fixed_table_tags.clone())?; config.load_byte_table(layouter)?; - config.execution.assign_block(layouter, block) + config.execution.assign_block(layouter, block, challenges) } } @@ -274,14 +274,14 @@ pub mod test { evm_circuit::{witness::Block, EvmCircuitConfig}, exp_circuit::OFFSET_INCREMENT, table::{BlockTable, BytecodeTable, CopyTable, ExpTable, KeccakTable, RwTable, TxTable}, - util::{power_of_randomness_from_instance, Challenges}, + util::Challenges, witness::block_convert, }; use bus_mapping::{circuit_input_builder::CircuitsParams, mock::BlockData}; use eth_types::{geth_types::GethData, Field, Word}; use halo2_proofs::halo2curves::bn256::Fr; use halo2_proofs::{ - circuit::{Layouter, SimpleFloorPlanner, Value}, + circuit::{Layouter, SimpleFloorPlanner}, dev::{MockProver, VerifyFailure}, plonk::{Circuit, ConstraintSystem, Error}, }; @@ -311,7 +311,7 @@ pub mod test { } impl Circuit for EvmCircuit { - type Config = EvmCircuitConfig; + type Config = (EvmCircuitConfig, Challenges); type FloorPlanner = SimpleFloorPlanner; fn without_witnesses(&self) -> Self { @@ -327,20 +327,24 @@ pub mod test { let copy_table = CopyTable::construct(meta, q_copy_table); let keccak_table = KeccakTable::construct(meta); let exp_table = ExpTable::construct(meta); - - let power_of_randomness = power_of_randomness_from_instance(meta); - EvmCircuitConfig::new( - meta, - EvmCircuitConfigArgs { - power_of_randomness, - tx_table, - rw_table, - bytecode_table, - block_table, - copy_table, - keccak_table, - exp_table, - }, + let challenges = Challenges::construct(meta); + let challenges_expr = challenges.exprs(meta); + + ( + EvmCircuitConfig::new( + meta, + EvmCircuitConfigArgs { + challenges: challenges_expr, + tx_table, + rw_table, + bytecode_table, + block_table, + copy_table, + keccak_table, + exp_table, + }, + ), + challenges, ) } @@ -350,10 +354,9 @@ pub mod test { mut layouter: impl Layouter, ) -> Result<(), Error> { let block = self.block.as_ref().unwrap(); - let challenges = Challenges::mock( - Value::known(block.randomness), - Value::known(block.randomness), - ); + + let (config, challenges) = config; + let challenges = challenges.values(&mut layouter); config.tx_table.load( &mut layouter, @@ -366,14 +369,14 @@ pub mod test { &mut layouter, &block.rws.table_assignments(), block.circuits_params.max_rws, - Value::known(block.randomness), + challenges.evm_word(), )?; config .bytecode_table .load(&mut layouter, block.bytecodes.values(), &challenges)?; config .block_table - .load(&mut layouter, &block.context, block.randomness)?; + .load(&mut layouter, &block.context, challenges.evm_word())?; config.copy_table.load(&mut layouter, block, &challenges)?; config .keccak_table @@ -388,13 +391,13 @@ pub mod test { pub fn get_num_rows_required(block: &Block) -> usize { let mut cs = ConstraintSystem::default(); let config = EvmCircuit::::configure(&mut cs); - config.get_num_rows_required(block) + config.0.get_num_rows_required(block) } pub fn get_active_rows(block: &Block) -> (Vec, Vec) { let mut cs = ConstraintSystem::default(); let config = EvmCircuit::::configure(&mut cs); - config.get_active_rows(block) + config.0.get_active_rows(block) } } @@ -482,23 +485,13 @@ pub mod test { EvmCircuit::::new_dev(block, fixed_table_tags) } - pub fn get_test_instance(block: &Block) -> Vec> { - let k = get_test_degree(block); - - (1..32) - .map(|exp| vec![block.randomness.pow(&[exp, 0, 0, 0]); (1 << k) - 64]) - .collect() - } - pub fn run_test_circuit(block: Block) -> Result<(), Vec> { let k = get_test_degree(&block); let (active_gate_rows, active_lookup_rows) = EvmCircuit::::get_active_rows(&block); - let power_of_randomness = get_test_instance(&block); - let circuit = get_test_cicuit_from_block(block); - let prover = MockProver::::run(k, &circuit, power_of_randomness).unwrap(); + let prover = MockProver::::run(k, &circuit, vec![]).unwrap(); prover.verify_at_rows_par(active_gate_rows.into_iter(), active_lookup_rows.into_iter()) } } @@ -559,7 +552,7 @@ mod evm_circuit_stats { let mut implemented_states = Vec::new(); for state in ExecutionState::iter() { - let height = circuit.execution.get_step_height_option(state); + let height = circuit.0.execution.get_step_height_option(state); if let Some(h) = height { implemented_states.push((state, h)); } diff --git a/zkevm-circuits/src/evm_circuit/execution.rs b/zkevm-circuits/src/evm_circuit/execution.rs index 7df1f53320..b19a0fb868 100644 --- a/zkevm-circuits/src/evm_circuit/execution.rs +++ b/zkevm-circuits/src/evm_circuit/execution.rs @@ -1,7 +1,7 @@ use super::util::{CachedRegion, CellManager, StoredExpression}; use crate::{ evm_circuit::{ - param::{MAX_STEP_HEIGHT, STEP_WIDTH}, + param::{LOOKUP_CONFIG, MAX_STEP_HEIGHT, N_PHASE2_COLUMNS, N_PHASE3_COLUMNS, STEP_WIDTH}, step::{ExecutionState, Step}, table::Table, util::{ @@ -11,14 +11,17 @@ use crate::{ witness::{Block, Call, ExecStep, Transaction}, }, table::LookupTable, - util::{query_expression, Expr}, + util::{query_expression, Challenges, Expr}, }; use eth_types::Field; use gadgets::util::not; use halo2_proofs::{ arithmetic::FieldExt, circuit::{Layouter, Region, Value}, - plonk::{Advice, Column, ConstraintSystem, Error, Expression, Fixed, Selector, VirtualCells}, + plonk::{ + Advice, Column, ConstraintSystem, Error, Expression, FirstPhase, Fixed, SecondPhase, + Selector, ThirdPhase, VirtualCells, + }, poly::Rotation, }; use std::{ @@ -289,7 +292,7 @@ impl ExecutionConfig { #[allow(clippy::too_many_arguments)] pub(crate) fn configure( meta: &mut ConstraintSystem, - power_of_randomness: [Expression; 31], + challenges: Challenges>, fixed_table: &dyn LookupTable, byte_table: &dyn LookupTable, tx_table: &dyn LookupTable, @@ -308,7 +311,24 @@ impl ExecutionConfig { let num_rows_inv = meta.advice_column(); let q_step_first = meta.complex_selector(); let q_step_last = meta.complex_selector(); - let advices = [(); STEP_WIDTH].map(|_| meta.advice_column()); + + let lookup_column_count: usize = LOOKUP_CONFIG.iter().map(|(_, count)| *count).sum(); + + let advices = [(); STEP_WIDTH] + .iter() + .enumerate() + .map(|(n, _)| { + if n < N_PHASE3_COLUMNS + lookup_column_count { + meta.advice_column_in(ThirdPhase) + } else if n < N_PHASE3_COLUMNS + lookup_column_count + N_PHASE2_COLUMNS { + meta.advice_column_in(SecondPhase) + } else { + meta.advice_column_in(FirstPhase) + } + }) + .collect::>() + .try_into() + .unwrap(); let step_curr = Step::new(meta, advices, 0, false); let mut height_map = HashMap::new(); @@ -395,7 +415,10 @@ impl ExecutionConfig { }); let mut stored_expressions_map = HashMap::new(); + let step_next = Step::new(meta, advices, MAX_STEP_HEIGHT, true); + let word_powers_of_randomness = challenges.evm_word_powers_of_randomness(); + let lookup_powers_of_randomness = challenges.lookup_input_powers_of_randomness(); macro_rules! configure_gadget { () => { Self::configure_gadget( @@ -406,7 +429,9 @@ impl ExecutionConfig { num_rows_until_next_step, q_step_first, q_step_last, - &power_of_randomness, + &challenges, + &word_powers_of_randomness, + &lookup_powers_of_randomness, &step_curr, &step_next, &mut height_map, @@ -416,6 +441,7 @@ impl ExecutionConfig { } let cell_manager = step_curr.cell_manager.clone(); + let config = Self { q_usable, q_step, @@ -533,10 +559,9 @@ impl ExecutionConfig { copy_table, keccak_table, exp_table, - &power_of_randomness, + &challenges, &cell_manager, ); - config } @@ -558,7 +583,9 @@ impl ExecutionConfig { num_rows_until_next_step: Column, q_step_first: Selector, q_step_last: Selector, - power_of_randomness: &[Expression; 31], + challenges: &Challenges>, + word_powers_of_randomness: &[Expression; 31], + lookup_powers_of_randomness: &[Expression; 12], step_curr: &Step, step_next: &Step, height_map: &mut HashMap, @@ -570,7 +597,9 @@ impl ExecutionConfig { let mut cb = ConstraintBuilder::new( step_curr.clone(), step_next.clone(), - power_of_randomness, + challenges, + word_powers_of_randomness, + lookup_powers_of_randomness, G::EXECUTION_STATE, ); G::configure(&mut cb); @@ -583,7 +612,9 @@ impl ExecutionConfig { let mut cb = ConstraintBuilder::new( step_curr.clone(), step_next.clone(), - power_of_randomness, + challenges, + word_powers_of_randomness, + lookup_powers_of_randomness, G::EXECUTION_STATE, ); @@ -604,6 +635,7 @@ impl ExecutionConfig { !height_map.contains_key(&G::EXECUTION_STATE), "execution state already configured" ); + height_map.insert(G::EXECUTION_STATE, height); debug_assert!( !stored_expressions_map.contains_key(&G::EXECUTION_STATE), @@ -621,6 +653,7 @@ impl ExecutionConfig { let sel_not_step_last: &dyn Fn(&mut VirtualCells) -> Expression = &|meta| { meta.query_advice(q_step, Rotation::cur()) * not::expr(meta.query_selector(q_step_last)) }; + for (selector, constraints) in [ (sel_step, constraints.step), (sel_step_first, constraints.step_first), @@ -713,9 +746,11 @@ impl ExecutionConfig { copy_table: &dyn LookupTable, keccak_table: &dyn LookupTable, exp_table: &dyn LookupTable, - power_of_randomness: &[Expression; 31], + challenges: &Challenges>, cell_manager: &CellManager, ) { + let lookup_powers_of_randomness: [Expression; 31] = + challenges.lookup_input_powers_of_randomness(); for column in cell_manager.columns().iter() { if let CellType::Lookup(table) = column.cell_type { let name = format!("{:?}", table); @@ -734,7 +769,7 @@ impl ExecutionConfig { .table_exprs(meta); vec![( column.expr(), - rlc::expr(&table_expressions, power_of_randomness), + rlc::expr(&table_expressions, &lookup_powers_of_randomness), )] }); } @@ -785,13 +820,8 @@ impl ExecutionConfig { &self, layouter: &mut impl Layouter, block: &Block, + challenges: &Challenges>, ) -> 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| { @@ -842,7 +872,7 @@ impl ExecutionConfig { step, height, next.copied(), - power_of_randomness, + challenges, )?; // q_step logic @@ -878,7 +908,7 @@ impl ExecutionConfig { &last_call, end_block_not_last, height, - power_of_randomness, + challenges, )?; for row_idx in offset..last_row { @@ -900,7 +930,7 @@ impl ExecutionConfig { end_block_last, height, None, - power_of_randomness, + challenges, )?; self.assign_q_step(&mut region, offset, height)?; // enable q_step_last @@ -939,7 +969,7 @@ impl ExecutionConfig { call: &Call, step: &ExecStep, height: usize, - power_of_randomness: [F; 31], + challenges: &Challenges>, ) -> Result<(), Error> { if offset_end <= offset_begin { return Ok(()); @@ -951,7 +981,7 @@ impl ExecutionConfig { // Disable access to next step deliberately for "repeatable" step let region = &mut CachedRegion::<'_, '_, F>::new( region, - power_of_randomness, + challenges, self.advices.to_vec(), 1, offset_begin, @@ -978,7 +1008,7 @@ impl ExecutionConfig { step: &ExecStep, height: usize, next: Option<(&Transaction, &Call, &ExecStep)>, - power_of_randomness: [F; 31], + challenges: &Challenges>, ) -> Result<(), Error> { if !matches!(step.execution_state, ExecutionState::EndBlock) { log::trace!( @@ -994,7 +1024,7 @@ impl ExecutionConfig { // enough for 3 steps. let region = &mut CachedRegion::<'_, '_, F>::new( region, - power_of_randomness, + challenges, self.advices.to_vec(), MAX_STEP_HEIGHT * 3, offset, @@ -1196,12 +1226,13 @@ impl ExecutionConfig { // enable with `RUST_LOG=debug` if log::log_enabled!(log::Level::Debug) { - let is_padding_step = matches!(step.execution_state, ExecutionState::EndBlock) - && step.rw_indices.is_empty(); - if !is_padding_step { - // expensive function call - Self::check_rw_lookup(&assigned_stored_expressions, step, block); - } + // expensive function call + Self::check_rw_lookup( + &assigned_stored_expressions, + step, + block, + region.challenges(), + ); } //} Ok(()) @@ -1232,6 +1263,7 @@ impl ExecutionConfig { assigned_stored_expressions: &[(String, F)], step: &ExecStep, block: &Block, + challenges: &Challenges>, ) { let mut assigned_rw_values = Vec::new(); // Reversion lookup expressions have different ordering compared to rw table, @@ -1252,21 +1284,26 @@ impl ExecutionConfig { .table_assignments() .iter() .map(|rw| { - rw.table_assignment_aux(block.randomness) - .rlc(block.randomness) + challenges + .evm_word() + .map(|randomness| rw.table_assignment_aux(randomness).rlc(randomness)) }) - .collect(); + .fold(BTreeSet::::new(), |mut set, value| { + value.map(|value| set.insert(value)); + set + }); for (name, value) in assigned_rw_values.iter() { if !rlc_assignments.contains(value) { log::error!("rw lookup error: name: {}, step: {:?}", *name, step); } } + challenges.evm_word().map(|randomness| { for (idx, assigned_rw_value) in assigned_rw_values.iter().enumerate() { let rw_idx = step.rw_indices[idx]; let rw = block.rws[rw_idx]; - let table_assignments = rw.table_assignment_aux(block.randomness); - let rlc = table_assignments.rlc(block.randomness); + let table_assignments = rw.table_assignment_aux(randomness); + let rlc = table_assignments.rlc(randomness); if rlc != assigned_rw_value.1 { log::error!( "incorrect rw witness. lookup input name: \"{}\"\n{:?}\nrw: {:?}, rw index: {:?}, {}th rw of step {:?}", @@ -1278,5 +1315,6 @@ impl ExecutionConfig { step.execution_state); } } + }); } } diff --git a/zkevm-circuits/src/evm_circuit/execution/add_sub.rs b/zkevm-circuits/src/evm_circuit/execution/add_sub.rs index 47e68c7074..fed97020e3 100644 --- a/zkevm-circuits/src/evm_circuit/execution/add_sub.rs +++ b/zkevm-circuits/src/evm_circuit/execution/add_sub.rs @@ -35,9 +35,9 @@ impl ExecutionGadget for AddSubGadget { fn configure(cb: &mut ConstraintBuilder) -> Self { let opcode = cb.query_cell(); - let a = cb.query_word(); - let b = cb.query_word(); - let c = cb.query_word(); + let a = cb.query_word_rlc(); + let b = cb.query_word_rlc(); + let c = cb.query_word_rlc(); let add_words = AddWordsGadget::construct(cb, [a.clone(), b.clone()], c.clone()); // Swap a and c if opcode is SUB diff --git a/zkevm-circuits/src/evm_circuit/execution/addmod.rs b/zkevm-circuits/src/evm_circuit/execution/addmod.rs index 449d6172c6..eee053570c 100644 --- a/zkevm-circuits/src/evm_circuit/execution/addmod.rs +++ b/zkevm-circuits/src/evm_circuit/execution/addmod.rs @@ -53,15 +53,15 @@ impl ExecutionGadget for AddModGadget { let opcode = cb.query_cell(); // values got from stack (original r is modified if n==0) - let a = cb.query_word(); - let b = cb.query_word(); - let n = cb.query_word(); - let r = cb.query_word(); + let a = cb.query_word_rlc(); + let b = cb.query_word_rlc(); + let n = cb.query_word_rlc(); + let r = cb.query_word_rlc(); // auxiliar witness - let k = cb.query_word(); - let a_reduced = cb.query_word(); - let d = cb.query_word(); + let k = cb.query_word_rlc(); + let a_reduced = cb.query_word_rlc(); + let d = cb.query_word_rlc(); let n_is_zero = IsZeroGadget::construct(cb, n.clone().expr()); @@ -74,10 +74,10 @@ impl ExecutionGadget for AddModGadget { // 2. check d * N + r == a_reduced + b, only checking carry if n != 0 let sum_areduced_b = { - let sum = cb.query_word(); + let sum = cb.query_word_rlc(); AddWordsGadget::construct(cb, [a_reduced.clone(), b.clone()], sum) }; - let sum_areduced_b_overflow = cb.query_word(); + let sum_areduced_b_overflow = cb.query_word_rlc(); let muladd_d_n_r = MulAddWords512Gadget::construct( cb, [&d, &n, &sum_areduced_b_overflow, sum_areduced_b.sum()], @@ -213,11 +213,8 @@ impl ExecutionGadget for AddModGadget { self.cmp_r_n.assign(region, offset, r, n)?; self.cmp_areduced_n.assign(region, offset, a_reduced, n)?; - self.n_is_zero.assign( - region, - offset, - Word::random_linear_combine(n.to_le_bytes(), block.randomness), - )?; + self.n_is_zero + .assign_value(region, offset, region.word_rlc(n))?; Ok(()) } diff --git a/zkevm-circuits/src/evm_circuit/execution/address.rs b/zkevm-circuits/src/evm_circuit/execution/address.rs index 14e97f7ac0..63729e3e9d 100644 --- a/zkevm-circuits/src/evm_circuit/execution/address.rs +++ b/zkevm-circuits/src/evm_circuit/execution/address.rs @@ -30,7 +30,7 @@ impl ExecutionGadget for AddressGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::ADDRESS; fn configure(cb: &mut ConstraintBuilder) -> Self { - let address = cb.query_rlc(); + let address = cb.query_word_rlc(); // Lookup callee address in call context. cb.call_context_lookup( diff --git a/zkevm-circuits/src/evm_circuit/execution/balance.rs b/zkevm-circuits/src/evm_circuit/execution/balance.rs index edfe918fb7..fe72f66c08 100644 --- a/zkevm-circuits/src/evm_circuit/execution/balance.rs +++ b/zkevm-circuits/src/evm_circuit/execution/balance.rs @@ -6,9 +6,7 @@ use crate::evm_circuit::util::constraint_builder::Transition::Delta; use crate::evm_circuit::util::constraint_builder::{ ConstraintBuilder, ReversionInfo, StepStateTransition, }; -use crate::evm_circuit::util::{ - from_bytes, select, CachedRegion, Cell, RandomLinearCombination, Word, -}; +use crate::evm_circuit::util::{from_bytes, select, CachedRegion, Cell, Word}; use crate::evm_circuit::witness::{Block, Call, ExecStep, Rw, Transaction}; use crate::table::{AccountFieldTag, CallContextFieldTag}; use crate::util::Expr; @@ -34,7 +32,7 @@ impl ExecutionGadget for BalanceGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::BALANCE; fn configure(cb: &mut ConstraintBuilder) -> Self { - let address_word = cb.query_word(); + let address_word = cb.query_word_rlc(); let address = from_bytes::expr(&address_word.cells[..N_BYTES_ACCOUNT_ADDRESS]); cb.stack_pop(address_word.expr()); @@ -130,14 +128,8 @@ impl ExecutionGadget for BalanceGadget { } => (0.into(), false), _ => unreachable!(), }; - self.balance.assign( - region, - offset, - Value::known(RandomLinearCombination::random_linear_combine( - balance.to_le_bytes(), - block.randomness, - )), - )?; + self.balance + .assign(region, offset, region.word_rlc(balance))?; self.exists .assign(region, offset, Value::known(F::from(exists)))?; diff --git a/zkevm-circuits/src/evm_circuit/execution/begin_tx.rs b/zkevm-circuits/src/evm_circuit/execution/begin_tx.rs index 1892f2e372..cd438f197c 100644 --- a/zkevm-circuits/src/evm_circuit/execution/begin_tx.rs +++ b/zkevm-circuits/src/evm_circuit/execution/begin_tx.rs @@ -10,7 +10,7 @@ use crate::{ Transition::{Delta, To}, }, math_gadget::{IsEqualGadget, IsZeroGadget, MulWordByU64Gadget, RangeCheckGadget}, - select, CachedRegion, Cell, RandomLinearCombination, Word, + select, CachedRegion, Cell, CellType, Word, }, witness::{Block, Call, ExecStep, Transaction}, }, @@ -20,7 +20,6 @@ use crate::{ use eth_types::{evm_types::GasCost, Field, ToLittleEndian, ToScalar}; use halo2_proofs::circuit::Value; use halo2_proofs::plonk::Error; -use keccak256::EMPTY_HASH_LE; #[derive(Clone, Debug)] pub(crate) struct BeginTxGadget { @@ -39,7 +38,7 @@ pub(crate) struct BeginTxGadget { reversion_info: ReversionInfo, sufficient_gas_left: RangeCheckGadget, transfer_with_gas_fee: TransferWithGasFeeGadget, - code_hash: Cell, + phase2_code_hash: Cell, is_empty_code_hash: IsEqualGadget, } @@ -150,21 +149,15 @@ impl ExecutionGadget for BeginTxGadget { // TODO: Handle precompiled // Read code_hash of callee - let code_hash = cb.query_cell(); + let phase2_code_hash = cb.query_cell_with_type(CellType::StoragePhase2); cb.account_read( tx_callee_address.expr(), AccountFieldTag::CodeHash, - code_hash.expr(), + phase2_code_hash.expr(), ); - let is_empty_code_hash = IsEqualGadget::construct( - cb, - code_hash.expr(), - Word::random_linear_combine_expr( - (*EMPTY_HASH_LE).map(|byte| byte.expr()), - cb.power_of_randomness(), - ), - ); + let is_empty_code_hash = + IsEqualGadget::construct(cb, phase2_code_hash.expr(), cb.empty_hash_rlc()); cb.condition(is_empty_code_hash.expr(), |cb| { cb.require_equal( @@ -214,7 +207,7 @@ impl ExecutionGadget for BeginTxGadget { (CallContextFieldTag::LastCalleeReturnDataLength, 0.expr()), (CallContextFieldTag::IsRoot, 1.expr()), (CallContextFieldTag::IsCreate, tx_is_create.expr()), - (CallContextFieldTag::CodeHash, code_hash.expr()), + (CallContextFieldTag::CodeHash, phase2_code_hash.expr()), ] { cb.call_context_lookup(true.expr(), Some(call_id.expr()), field_tag, value); } @@ -248,7 +241,7 @@ impl ExecutionGadget for BeginTxGadget { call_id: To(call_id.expr()), is_root: To(true.expr()), is_create: To(tx_is_create.expr()), - code_hash: To(code_hash.expr()), + code_hash: To(phase2_code_hash.expr()), gas_left: To(gas_left), reversible_write_counter: To(2.expr()), log_id: To(0.expr()), @@ -272,7 +265,7 @@ impl ExecutionGadget for BeginTxGadget { reversion_info, sufficient_gas_left, transfer_with_gas_fee, - code_hash, + phase2_code_hash, is_empty_code_hash, } } @@ -346,19 +339,13 @@ impl ExecutionGadget for BeginTxGadget { tx.value, gas_fee, )?; - self.code_hash.assign( - region, - offset, - Value::known(RandomLinearCombination::random_linear_combine( - callee_code_hash.to_le_bytes(), - block.randomness, - )), - )?; - self.is_empty_code_hash.assign( + self.phase2_code_hash + .assign(region, offset, region.word_rlc(callee_code_hash))?; + self.is_empty_code_hash.assign_value( region, offset, - Word::random_linear_combine(callee_code_hash.to_le_bytes(), block.randomness), - Word::random_linear_combine(*EMPTY_HASH_LE, block.randomness), + region.word_rlc(callee_code_hash), + region.empty_hash_rlc(), )?; Ok(()) } diff --git a/zkevm-circuits/src/evm_circuit/execution/bitwise.rs b/zkevm-circuits/src/evm_circuit/execution/bitwise.rs index 476c4aef63..f6ca8fed4d 100644 --- a/zkevm-circuits/src/evm_circuit/execution/bitwise.rs +++ b/zkevm-circuits/src/evm_circuit/execution/bitwise.rs @@ -33,9 +33,9 @@ impl ExecutionGadget for BitwiseGadget { fn configure(cb: &mut ConstraintBuilder) -> Self { let opcode = cb.query_cell(); - let a = cb.query_word(); - let b = cb.query_word(); - let c = cb.query_word(); + let a = cb.query_word_rlc(); + let b = cb.query_word_rlc(); + let c = cb.query_word_rlc(); cb.stack_pop(a.expr()); cb.stack_pop(b.expr()); diff --git a/zkevm-circuits/src/evm_circuit/execution/block_ctx.rs b/zkevm-circuits/src/evm_circuit/execution/block_ctx.rs index 86f62ef30b..a580fe4557 100644 --- a/zkevm-circuits/src/evm_circuit/execution/block_ctx.rs +++ b/zkevm-circuits/src/evm_circuit/execution/block_ctx.rs @@ -26,7 +26,7 @@ pub(crate) struct BlockCtxGadget { impl BlockCtxGadget { fn construct(cb: &mut ConstraintBuilder) -> Self { - let value = cb.query_rlc(); + let value = cb.query_word_rlc(); // Push the const generic parameter N_BYTES value to the stack cb.stack_push(value.expr()); diff --git a/zkevm-circuits/src/evm_circuit/execution/blockhash.rs b/zkevm-circuits/src/evm_circuit/execution/blockhash.rs index 14e34d2ccc..df512e7442 100644 --- a/zkevm-circuits/src/evm_circuit/execution/blockhash.rs +++ b/zkevm-circuits/src/evm_circuit/execution/blockhash.rs @@ -36,7 +36,7 @@ impl ExecutionGadget for BlockHashGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::BLOCKHASH; fn configure(cb: &mut ConstraintBuilder) -> Self { - let block_number = cb.query_rlc(); + let block_number = cb.query_word_rlc(); cb.stack_pop(block_number.expr()); let current_block_number = cb.query_cell(); @@ -58,7 +58,7 @@ impl ExecutionGadget for BlockHashGadget { 257.expr() + from_bytes::expr(&block_number.cells), ); - let block_hash = cb.query_rlc(); + let block_hash = cb.query_word_rlc(); cb.condition(block_lt.expr() * diff_lt.expr(), |cb| { cb.block_lookup( BlockContextFieldTag::BlockHash.expr(), diff --git a/zkevm-circuits/src/evm_circuit/execution/byte.rs b/zkevm-circuits/src/evm_circuit/execution/byte.rs index 0336d3a6a0..085f39abe2 100644 --- a/zkevm-circuits/src/evm_circuit/execution/byte.rs +++ b/zkevm-circuits/src/evm_circuit/execution/byte.rs @@ -33,8 +33,8 @@ impl ExecutionGadget for ByteGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::BYTE; fn configure(cb: &mut ConstraintBuilder) -> Self { - let index = cb.query_word(); - let value = cb.query_word(); + let index = cb.query_word_rlc(); + let value = cb.query_word_rlc(); // If any of the non-LSB bytes of the index word are non-zero we never // need to copy any bytes. So just sum all the non-LSB byte diff --git a/zkevm-circuits/src/evm_circuit/execution/calldatacopy.rs b/zkevm-circuits/src/evm_circuit/execution/calldatacopy.rs index 7046b7ad02..08b42ec188 100644 --- a/zkevm-circuits/src/evm_circuit/execution/calldatacopy.rs +++ b/zkevm-circuits/src/evm_circuit/execution/calldatacopy.rs @@ -46,8 +46,8 @@ impl ExecutionGadget for CallDataCopyGadget { let opcode = cb.query_cell(); let memory_offset = cb.query_cell(); - let data_offset = cb.query_rlc(); - let length = cb.query_rlc(); + let data_offset = cb.query_word_rlc(); + let length = cb.query_word_rlc(); // Pop memory_offset, data_offset, length from stack cb.stack_pop(memory_offset.expr()); @@ -172,9 +172,9 @@ impl ExecutionGadget for CallDataCopyGadget { let [memory_offset, data_offset, length] = [step.rw_indices[0], step.rw_indices[1], step.rw_indices[2]] .map(|idx| block.rws[idx].stack_value()); - let memory_address = - self.memory_address - .assign(region, offset, memory_offset, length, block.randomness)?; + let memory_address = self + .memory_address + .assign(region, offset, memory_offset, length)?; self.data_offset.assign( region, offset, diff --git a/zkevm-circuits/src/evm_circuit/execution/calldataload.rs b/zkevm-circuits/src/evm_circuit/execution/calldataload.rs index 600a190aa9..d35fe5fc57 100644 --- a/zkevm-circuits/src/evm_circuit/execution/calldataload.rs +++ b/zkevm-circuits/src/evm_circuit/execution/calldataload.rs @@ -14,7 +14,7 @@ use crate::{ constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, from_bytes, memory_gadget::BufferReaderGadget, - not, CachedRegion, Cell, MemoryAddress, RandomLinearCombination, + not, CachedRegion, Cell, MemoryAddress, }, witness::{Block, Call, ExecStep, Transaction}, }, @@ -56,7 +56,7 @@ impl ExecutionGadget for CallDataLoadGadget { fn configure(cb: &mut ConstraintBuilder) -> Self { let opcode = cb.query_cell(); - let offset = cb.query_rlc(); + let offset = cb.query_word_rlc(); // Pop the offset value from stack. cb.stack_pop(offset.expr()); @@ -143,10 +143,7 @@ impl ExecutionGadget for CallDataLoadGadget { // Add a lookup constraint for the 32-bytes that should have been pushed // to the stack. let calldata_word: [Expression; N_BYTES_WORD] = calldata_word.try_into().unwrap(); - cb.stack_push(RandomLinearCombination::random_linear_combine_expr( - calldata_word, - cb.power_of_randomness(), - )); + cb.stack_push(cb.word_rlc(calldata_word)); let step_state_transition = StepStateTransition { rw_counter: Delta(cb.rw_counter_offset()), diff --git a/zkevm-circuits/src/evm_circuit/execution/calldatasize.rs b/zkevm-circuits/src/evm_circuit/execution/calldatasize.rs index 315a862ef5..135974da62 100644 --- a/zkevm-circuits/src/evm_circuit/execution/calldatasize.rs +++ b/zkevm-circuits/src/evm_circuit/execution/calldatasize.rs @@ -32,7 +32,7 @@ impl ExecutionGadget for CallDataSizeGadget { let opcode = cb.query_cell(); // Add lookup constraint in the call context for the calldatasize field. - let call_data_size = cb.query_rlc(); + let call_data_size = cb.query_word_rlc(); cb.call_context_lookup( false.expr(), None, diff --git a/zkevm-circuits/src/evm_circuit/execution/caller.rs b/zkevm-circuits/src/evm_circuit/execution/caller.rs index 1ce018d30a..8648d58c47 100644 --- a/zkevm-circuits/src/evm_circuit/execution/caller.rs +++ b/zkevm-circuits/src/evm_circuit/execution/caller.rs @@ -30,7 +30,7 @@ impl ExecutionGadget for CallerGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::CALLER; fn configure(cb: &mut ConstraintBuilder) -> Self { - let caller_address = cb.query_rlc(); + let caller_address = cb.query_word_rlc(); // Lookup rw_table -> call_context with caller address cb.call_context_lookup( diff --git a/zkevm-circuits/src/evm_circuit/execution/callop.rs b/zkevm-circuits/src/evm_circuit/execution/callop.rs index f7ca4bdd58..e675cefe7f 100644 --- a/zkevm-circuits/src/evm_circuit/execution/callop.rs +++ b/zkevm-circuits/src/evm_circuit/execution/callop.rs @@ -11,7 +11,7 @@ use crate::evm_circuit::util::math_gadget::{ }; use crate::evm_circuit::util::memory_gadget::{MemoryAddressGadget, MemoryExpansionGadget}; use crate::evm_circuit::util::{ - from_bytes, not, or, select, sum, CachedRegion, Cell, RandomLinearCombination, Word, + from_bytes, not, or, select, sum, CachedRegion, Cell, CellType, Word, }; use crate::evm_circuit::witness::{Block, Call, ExecStep, Rw, Transaction}; use crate::table::{AccountFieldTag, CallContextFieldTag}; @@ -91,16 +91,16 @@ impl ExecutionGadget for CallOpGadget { 1.expr(), ); - let gas_word = cb.query_word(); - let code_address_word = cb.query_word(); - let value = cb.query_word(); + let gas_word = cb.query_word_rlc(); + let code_address_word = cb.query_word_rlc(); + let value = cb.query_word_rlc(); let cd_offset = cb.query_cell(); - let cd_length = cb.query_rlc(); + let cd_length = cb.query_word_rlc(); let rd_offset = cb.query_cell(); - let rd_length = cb.query_rlc(); + let rd_length = cb.query_word_rlc(); let is_success = cb.query_bool(); - let caller_balance_word = cb.query_word(); + let caller_balance_word = cb.query_word_rlc(); // Use rw_counter of the step which triggers next call as its call_id. let callee_call_id = cb.curr.state.rw_counter.clone(); @@ -251,7 +251,7 @@ impl ExecutionGadget for CallOpGadget { }); let callee_exists = cb.query_bool(); - let callee_code_hash = cb.query_cell(); + let callee_code_hash = cb.query_cell_with_type(CellType::StoragePhase2); cb.condition(callee_exists.expr(), |cb| { cb.account_read( code_address.expr(), @@ -263,14 +263,8 @@ impl ExecutionGadget for CallOpGadget { cb.account_read(code_address, AccountFieldTag::NonExisting, 0.expr()); }); - let is_empty_code_hash = IsEqualGadget::construct( - cb, - callee_code_hash.expr(), - Word::random_linear_combine_expr( - (*EMPTY_HASH_LE).map(|byte| byte.expr()), - cb.power_of_randomness(), - ), - ); + let is_empty_code_hash = + IsEqualGadget::construct(cb, callee_code_hash.expr(), cb.empty_hash_rlc()); // Sum up and verify gas cost. let gas_cost = select::expr( @@ -586,8 +580,8 @@ impl ExecutionGadget for CallOpGadget { } => (*EMPTY_HASH_LE, false), _ => unreachable!(), }; - let callee_code_hash = - RandomLinearCombination::random_linear_combine(callee_code_hash, block.randomness); + let callee_code_hash = region.word_rlc(U256::from_little_endian(&callee_code_hash)); + self.opcode .assign(region, offset, Value::known(F::from(opcode.as_u64())))?; self.is_call.assign( @@ -666,12 +660,12 @@ impl ExecutionGadget for CallOpGadget { )?; self.value_is_zero .assign(region, offset, sum::value(&value.to_le_bytes()))?; - let cd_address = - self.cd_address - .assign(region, offset, cd_offset, cd_length, block.randomness)?; - let rd_address = - self.rd_address - .assign(region, offset, rd_offset, rd_length, block.randomness)?; + let cd_address = self + .cd_address + .assign(region, offset, cd_offset, cd_length)?; + let rd_address = self + .rd_address + .assign(region, offset, rd_offset, rd_length)?; let (_, memory_expansion_gas_cost) = self.memory_expansion.assign( region, offset, @@ -692,12 +686,12 @@ impl ExecutionGadget for CallOpGadget { self.callee_exists .assign(region, offset, Value::known(F::from(callee_exists)))?; self.callee_code_hash - .assign(region, offset, Value::known(callee_code_hash))?; - self.is_empty_code_hash.assign( + .assign(region, offset, callee_code_hash)?; + self.is_empty_code_hash.assign_value( region, offset, callee_code_hash, - Word::random_linear_combine(*EMPTY_HASH_LE, block.randomness), + region.empty_hash_rlc(), )?; let has_value = !value.is_zero() && !is_delegatecall; let gas_cost = if is_warm_prev { @@ -719,7 +713,7 @@ impl ExecutionGadget for CallOpGadget { let gas_available = step.gas_left - gas_cost; self.one_64th_gas - .assign(region, offset, gas_available as u128)?; + .assign(region, offset, gas_available.into())?; self.capped_callee_gas_left.assign( region, offset, @@ -975,6 +969,14 @@ mod test { } } + #[test] + fn callop_base() { + test_ok( + caller(&OpcodeId::CALL, Stack::default(), true), + callee(bytecode! {}), + ); + } + fn test_ok(caller: Account, callee: Account) { let block: GethData = TestContext::<3, 1>::new( None, diff --git a/zkevm-circuits/src/evm_circuit/execution/callvalue.rs b/zkevm-circuits/src/evm_circuit/execution/callvalue.rs index 9e4d1a6c0a..25343998fa 100644 --- a/zkevm-circuits/src/evm_circuit/execution/callvalue.rs +++ b/zkevm-circuits/src/evm_circuit/execution/callvalue.rs @@ -5,7 +5,7 @@ use crate::{ util::{ common_gadget::SameContextGadget, constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, - CachedRegion, Cell, Word, + CachedRegion, Cell, }, witness::{Block, Call, ExecStep, Transaction}, }, @@ -13,8 +13,8 @@ use crate::{ util::Expr, }; use bus_mapping::evm::OpcodeId; -use eth_types::{Field, ToLittleEndian}; -use halo2_proofs::{circuit::Value, plonk::Error}; +use eth_types::Field; +use halo2_proofs::plonk::Error; #[derive(Clone, Debug)] pub(crate) struct CallValueGadget { @@ -73,14 +73,8 @@ impl ExecutionGadget for CallValueGadget { let call_value = block.rws[step.rw_indices[1]].stack_value(); - self.call_value.assign( - region, - offset, - Value::known(Word::random_linear_combine( - call_value.to_le_bytes(), - block.randomness, - )), - )?; + self.call_value + .assign(region, offset, region.word_rlc(call_value))?; Ok(()) } diff --git a/zkevm-circuits/src/evm_circuit/execution/chainid.rs b/zkevm-circuits/src/evm_circuit/execution/chainid.rs index 50523a92ee..6b48f31b3b 100644 --- a/zkevm-circuits/src/evm_circuit/execution/chainid.rs +++ b/zkevm-circuits/src/evm_circuit/execution/chainid.rs @@ -5,7 +5,7 @@ use crate::{ util::{ common_gadget::SameContextGadget, constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, - CachedRegion, Cell, Word, + CachedRegion, Cell, }, witness::{Block, Call, ExecStep, Transaction}, }, @@ -13,8 +13,8 @@ use crate::{ util::Expr, }; use bus_mapping::evm::OpcodeId; -use eth_types::{Field, ToLittleEndian}; -use halo2_proofs::{circuit::Value, plonk::Error}; +use eth_types::Field; +use halo2_proofs::plonk::Error; #[derive(Clone, Debug)] pub(crate) struct ChainIdGadget { @@ -65,14 +65,8 @@ impl ExecutionGadget for ChainIdGadget { self.same_context.assign_exec_step(region, offset, step)?; let chain_id = block.rws[step.rw_indices[0]].stack_value(); - self.chain_id.assign( - region, - offset, - Value::known(Word::random_linear_combine( - chain_id.to_le_bytes(), - block.randomness, - )), - )?; + self.chain_id + .assign(region, offset, region.word_rlc(chain_id))?; Ok(()) } } diff --git a/zkevm-circuits/src/evm_circuit/execution/codecopy.rs b/zkevm-circuits/src/evm_circuit/execution/codecopy.rs index b877706a15..00059aff4a 100644 --- a/zkevm-circuits/src/evm_circuit/execution/codecopy.rs +++ b/zkevm-circuits/src/evm_circuit/execution/codecopy.rs @@ -51,8 +51,8 @@ impl ExecutionGadget for CodeCopyGadget { // Query elements to be popped from the stack. let dst_memory_offset = cb.query_cell(); - let code_offset = cb.query_rlc(); - let size = cb.query_rlc(); + let code_offset = cb.query_word_rlc(); + let size = cb.query_word_rlc(); // Pop items from stack. cb.stack_pop(dst_memory_offset.expr()); @@ -166,9 +166,9 @@ impl ExecutionGadget for CodeCopyGadget { )?; // assign the destination memory offset. - let memory_address = - self.dst_memory_addr - .assign(region, offset, dest_offset, size, block.randomness)?; + let memory_address = self + .dst_memory_addr + .assign(region, offset, dest_offset, size)?; // assign to gadgets handling memory expansion cost and copying cost. let (_, memory_expansion_cost) = self.memory_expansion.assign( diff --git a/zkevm-circuits/src/evm_circuit/execution/codesize.rs b/zkevm-circuits/src/evm_circuit/execution/codesize.rs index 31fe295452..9e264187fb 100644 --- a/zkevm-circuits/src/evm_circuit/execution/codesize.rs +++ b/zkevm-circuits/src/evm_circuit/execution/codesize.rs @@ -9,7 +9,7 @@ use crate::{ util::{ common_gadget::SameContextGadget, constraint_builder::{ConstraintBuilder, StepStateTransition, Transition}, - from_bytes, CachedRegion, Cell, RandomLinearCombination, + from_bytes, CachedRegion, Cell, }, witness::{Block, Call, ExecStep, Transaction}, }, @@ -44,10 +44,7 @@ impl ExecutionGadget for CodesizeGadget { codesize.expr(), ); - cb.stack_push(RandomLinearCombination::random_linear_combine_expr( - codesize_bytes.clone().map(|c| c.expr()), - cb.power_of_randomness(), - )); + cb.stack_push(cb.word_rlc(codesize_bytes.clone().map(|c| c.expr()))); let step_state_transition = StepStateTransition { gas_left: Transition::Delta(-OpcodeId::CODESIZE.constant_gas_cost().expr()), diff --git a/zkevm-circuits/src/evm_circuit/execution/comparator.rs b/zkevm-circuits/src/evm_circuit/execution/comparator.rs index 7358c43a25..148be4cb49 100644 --- a/zkevm-circuits/src/evm_circuit/execution/comparator.rs +++ b/zkevm-circuits/src/evm_circuit/execution/comparator.rs @@ -36,8 +36,8 @@ impl ExecutionGadget for ComparatorGadget { fn configure(cb: &mut ConstraintBuilder) -> Self { let opcode = cb.query_cell(); - let a = cb.query_word(); - let b = cb.query_word(); + let a = cb.query_word_rlc(); + let b = cb.query_word_rlc(); // Check if opcode is EQ let is_eq = IsEqualGadget::construct(cb, opcode.expr(), OpcodeId::EQ.expr()); diff --git a/zkevm-circuits/src/evm_circuit/execution/dummy.rs b/zkevm-circuits/src/evm_circuit/execution/dummy.rs index decf6917b8..55a5f13b65 100644 --- a/zkevm-circuits/src/evm_circuit/execution/dummy.rs +++ b/zkevm-circuits/src/evm_circuit/execution/dummy.rs @@ -26,8 +26,8 @@ impl const EXECUTION_STATE: ExecutionState = S; fn configure(cb: &mut ConstraintBuilder) -> Self { - let pops: [Word; N_POP] = [(); N_POP].map(|_| cb.query_word()); - let pushes: [Word; N_PUSH] = [(); N_PUSH].map(|_| cb.query_word()); + let pops: [Word; N_POP] = [(); N_POP].map(|_| cb.query_word_rlc()); + let pushes: [Word; N_PUSH] = [(); N_PUSH].map(|_| cb.query_word_rlc()); for pop in pops.iter() { cb.stack_pop(pop.expr()); } diff --git a/zkevm-circuits/src/evm_circuit/execution/dup.rs b/zkevm-circuits/src/evm_circuit/execution/dup.rs index 6dfe2911cb..6ac47e2cb0 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}, - CachedRegion, Cell, Word, + CachedRegion, Cell, CellType, }, witness::{Block, Call, ExecStep, Transaction}, }, util::Expr, }; -use eth_types::{evm_types::OpcodeId, Field, ToLittleEndian}; -use halo2_proofs::{circuit::Value, plonk::Error}; +use eth_types::{evm_types::OpcodeId, Field}; +use halo2_proofs::plonk::Error; #[derive(Clone, Debug)] pub(crate) struct DupGadget { @@ -28,7 +28,7 @@ impl ExecutionGadget for DupGadget { fn configure(cb: &mut ConstraintBuilder) -> Self { let opcode = cb.query_cell(); - let value = cb.query_cell(); + let value = cb.query_cell_with_type(CellType::StoragePhase2); // The stack index we have to peek, deduced from the 'x' value of 'dupx' // The offset starts at 0 for DUP1 @@ -66,14 +66,7 @@ impl ExecutionGadget for DupGadget { self.same_context.assign_exec_step(region, offset, step)?; let value = block.rws[step.rw_indices[0]].stack_value(); - self.value.assign( - region, - offset, - Value::known(Word::random_linear_combine( - value.to_le_bytes(), - block.randomness, - )), - )?; + self.value.assign(region, offset, region.word_rlc(value))?; Ok(()) } diff --git a/zkevm-circuits/src/evm_circuit/execution/end_tx.rs b/zkevm-circuits/src/evm_circuit/execution/end_tx.rs index 12dcff9d7c..cb4fff6f30 100644 --- a/zkevm-circuits/src/evm_circuit/execution/end_tx.rs +++ b/zkevm-circuits/src/evm_circuit/execution/end_tx.rs @@ -85,14 +85,14 @@ impl ExecutionGadget for EndTxGadget { // Add gas_used * effective_tip to coinbase's balance let coinbase = cb.query_cell(); - let base_fee = cb.query_word(); + let base_fee = cb.query_word_rlc(); for (tag, value) in [ (BlockContextFieldTag::Coinbase, coinbase.expr()), (BlockContextFieldTag::BaseFee, base_fee.expr()), ] { cb.block_lookup(tag.expr(), None, value); } - let effective_tip = cb.query_word(); + let effective_tip = cb.query_word_rlc(); let sub_gas_price_by_base_fee = AddWordsGadget::construct(cb, [effective_tip.clone(), base_fee], tx_gas_price); let mul_effective_tip_by_gas_used = diff --git a/zkevm-circuits/src/evm_circuit/execution/error_invalid_jump.rs b/zkevm-circuits/src/evm_circuit/execution/error_invalid_jump.rs index e17bfab625..ffd2740dd9 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_invalid_jump.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_invalid_jump.rs @@ -11,7 +11,7 @@ use crate::{ }, from_bytes, math_gadget::{IsEqualGadget, IsZeroGadget, LtGadget}, - CachedRegion, Cell, RandomLinearCombination, Word as RLCWord, + CachedRegion, Cell, CellType, RandomLinearCombination, }, witness::{Block, Call, ExecStep, Transaction}, }, @@ -32,7 +32,7 @@ pub(crate) struct ErrorInvalidJumpGadget { within_range: LtGadget, is_jump_dest: IsEqualGadget, is_jumpi: IsEqualGadget, - condition: Cell, + phase2_condition: Cell, is_condition_zero: IsZeroGadget, restore_context: RestoreContextGadget, } @@ -43,11 +43,11 @@ impl ExecutionGadget for ErrorInvalidJumpGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::ErrorInvalidJump; fn configure(cb: &mut ConstraintBuilder) -> Self { - let destination = cb.query_rlc(); + let destination = cb.query_word_rlc(); let opcode = cb.query_cell(); let value = cb.query_cell(); let is_code = cb.query_cell(); - let condition = cb.query_cell(); + let phase2_condition = cb.query_cell_with_type(CellType::StoragePhase2); cb.require_in_set( "ErrorInvalidJump only happend in JUMP or JUMPI", @@ -62,13 +62,13 @@ impl ExecutionGadget for ErrorInvalidJumpGadget { // first default this condition, if use will re-construct with real condition // value - let is_condition_zero = IsZeroGadget::construct(cb, condition.expr()); + let is_condition_zero = IsZeroGadget::construct(cb, phase2_condition.expr()); // Pop the value from the stack cb.stack_pop(destination.expr()); cb.condition(is_jumpi.expr(), |cb| { - cb.stack_pop(condition.expr()); + cb.stack_pop(phase2_condition.expr()); // if condition is zero, jump will not happen, so constrain condition not zero cb.require_zero("condition is not zero", is_condition_zero.expr()); }); @@ -139,7 +139,7 @@ impl ExecutionGadget for ErrorInvalidJumpGadget { within_range, is_jump_dest, is_jumpi, - condition, + phase2_condition, is_condition_zero, restore_context, } @@ -165,9 +165,7 @@ impl ExecutionGadget for ErrorInvalidJumpGadget { } else { Word::zero() }; - let condition_rlc = - RLCWord::random_linear_combine(condition.to_le_bytes(), block.randomness); - + let condition_rlc = region.word_rlc(condition); self.destination.assign( region, offset, @@ -218,10 +216,10 @@ impl ExecutionGadget for ErrorInvalidJumpGadget { F::from(OpcodeId::JUMPI.as_u64()), )?; - self.condition - .assign(region, offset, Value::known(condition_rlc))?; - self.is_condition_zero + self.phase2_condition .assign(region, offset, condition_rlc)?; + self.is_condition_zero + .assign_value(region, offset, condition_rlc)?; self.restore_context .assign(region, offset, block, call, step, 2 + is_jumpi as usize)?; diff --git a/zkevm-circuits/src/evm_circuit/execution/error_oog_call.rs b/zkevm-circuits/src/evm_circuit/execution/error_oog_call.rs index c68fec2ff4..a46537cd25 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_oog_call.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_oog_call.rs @@ -11,7 +11,7 @@ use crate::evm_circuit::{ from_bytes, math_gadget::{BatchedIsZeroGadget, IsEqualGadget, IsZeroGadget, LtGadget}, memory_gadget::{MemoryAddressGadget, MemoryExpansionGadget}, - select, sum, CachedRegion, Cell, Word, + select, sum, CachedRegion, Cell, CellType, Word, }, witness::{Block, Call, ExecStep, Transaction}, }; @@ -20,7 +20,6 @@ use crate::util::Expr; use bus_mapping::evm::OpcodeId; use eth_types::{evm_types::GasCost, Field, ToLittleEndian, ToScalar}; use halo2_proofs::{circuit::Value, plonk::Error}; -use keccak256::EMPTY_HASH_LE; #[derive(Clone, Debug)] pub(crate) struct ErrorOOGCallGadget { @@ -37,7 +36,7 @@ pub(crate) struct ErrorOOGCallGadget { memory_expansion: MemoryExpansionGadget, balance: Word, callee_nonce: Cell, - callee_code_hash: Cell, + phase2_callee_code_hash: Cell, is_empty_nonce_and_balance: BatchedIsZeroGadget, is_empty_code_hash: IsEqualGadget, insufficient_gas: LtGadget, @@ -60,14 +59,14 @@ impl ExecutionGadget for ErrorOOGCallGadget { OpcodeId::CALL.expr(), ); - let gas_word = cb.query_word(); - let callee_address_word = cb.query_word(); - let value = cb.query_word(); + let gas_word = cb.query_word_rlc(); + let callee_address_word = cb.query_word_rlc(); + let value = cb.query_word_rlc(); let cd_offset = cb.query_cell(); - let cd_length = cb.query_rlc(); + let cd_length = cb.query_word_rlc(); let rd_offset = cb.query_cell(); - let rd_length = cb.query_rlc(); - let balance = cb.query_word(); + let rd_length = cb.query_word_rlc(); + let balance = cb.query_word_rlc(); let tx_id = cb.call_context(None, CallContextFieldTag::TxId); @@ -104,22 +103,19 @@ impl ExecutionGadget for ErrorOOGCallGadget { ); // Verify gas cost - let [callee_nonce, callee_code_hash] = [AccountFieldTag::Nonce, AccountFieldTag::CodeHash] - .map(|field_tag| { - let value = cb.query_cell(); - cb.account_read(callee_address.clone(), field_tag, value.expr()); - value - }); + let [callee_nonce, phase2_callee_code_hash] = [ + (AccountFieldTag::Nonce, CellType::StoragePhase1), + (AccountFieldTag::CodeHash, CellType::StoragePhase2), + ] + .map(|(field_tag, cell_type)| { + let value = cb.query_cell_with_type(cell_type); + cb.account_read(callee_address.clone(), field_tag, value.expr()); + value + }); let is_empty_nonce_and_balance = BatchedIsZeroGadget::construct(cb, [callee_nonce.expr(), balance.expr()]); - let is_empty_code_hash = IsEqualGadget::construct( - cb, - callee_code_hash.expr(), - Word::random_linear_combine_expr( - (*EMPTY_HASH_LE).map(|byte| byte.expr()), - cb.power_of_randomness(), - ), - ); + let is_empty_code_hash = + IsEqualGadget::construct(cb, phase2_callee_code_hash.expr(), cb.empty_hash_rlc()); let is_empty_account = is_empty_nonce_and_balance.expr() * is_empty_code_hash.expr(); // Sum up gas cost let gas_cost = select::expr( @@ -189,7 +185,7 @@ impl ExecutionGadget for ErrorOOGCallGadget { memory_expansion, balance, callee_nonce, - callee_code_hash, + phase2_callee_code_hash, is_empty_nonce_and_balance, is_empty_code_hash, insufficient_gas, @@ -250,12 +246,12 @@ impl ExecutionGadget for ErrorOOGCallGadget { self.value_is_zero .assign(region, offset, sum::value(&value.to_le_bytes()))?; - let cd_address = - self.cd_address - .assign(region, offset, cd_offset, cd_length, block.randomness)?; - let rd_address = - self.rd_address - .assign(region, offset, rd_offset, rd_length, block.randomness)?; + let cd_address = self + .cd_address + .assign(region, offset, cd_offset, cd_length)?; + let rd_address = self + .rd_address + .assign(region, offset, rd_offset, rd_length)?; let (_, memory_expansion_gas_cost) = self.memory_expansion.assign( region, offset, @@ -276,47 +272,41 @@ impl ExecutionGadget for ErrorOOGCallGadget { .expect("unexpected U256 -> Scalar conversion failure"), ), )?; - self.callee_code_hash.assign( - region, - offset, - Value::known(Word::random_linear_combine( - callee_code_hash.to_le_bytes(), - block.randomness, - )), - )?; - let is_empty_nonce_and_balance = self.is_empty_nonce_and_balance.assign( + self.phase2_callee_code_hash + .assign(region, offset, region.word_rlc(callee_code_hash))?; + let is_empty_nonce_and_balance = self.is_empty_nonce_and_balance.assign_value( region, offset, [ - F::from(callee_nonce.low_u64()), - Word::random_linear_combine(callee_balance_pair.1.to_le_bytes(), block.randomness), + Value::known(F::from(callee_nonce.low_u64())), + region.word_rlc(callee_balance_pair.1), ], )?; - let is_empty_code_hash = self.is_empty_code_hash.assign( + let is_empty_code_hash = self.is_empty_code_hash.assign_value( region, offset, - Word::random_linear_combine(callee_code_hash.to_le_bytes(), block.randomness), - Word::random_linear_combine(*EMPTY_HASH_LE, block.randomness), + region.word_rlc(callee_code_hash), + region.empty_hash_rlc(), )?; let is_empty_account = is_empty_nonce_and_balance * is_empty_code_hash; let has_value = !value.is_zero(); let gas_cost = if is_warm_prev { - GasCost::WARM_ACCESS.as_u64() + Value::known(F::from(GasCost::WARM_ACCESS.as_u64())) } else { - GasCost::COLD_ACCOUNT_ACCESS.as_u64() + Value::known(F::from(GasCost::COLD_ACCOUNT_ACCESS.as_u64())) } + if has_value { - GasCost::CALL_WITH_VALUE.as_u64() - + if is_empty_account == F::one() { - GasCost::NEW_ACCOUNT.as_u64() - } else { - 0 - } + Value::known(F::from(GasCost::CALL_WITH_VALUE.as_u64())) + + is_empty_account * Value::known(F::from(GasCost::NEW_ACCOUNT.as_u64())) } else { - 0 - } + memory_expansion_gas_cost; + Value::known(F::from(0)) + } + Value::known(F::from(memory_expansion_gas_cost)); - self.insufficient_gas - .assign(region, offset, F::from(step.gas_left), F::from(gas_cost))?; + self.insufficient_gas.assign_value( + region, + offset, + Value::known(F::from(step.gas_left)), + gas_cost, + )?; self.restore_context .assign(region, offset, block, call, step, 15)?; 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 ac8f93456d..596885b855 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 @@ -45,7 +45,7 @@ impl ExecutionGadget for ErrorOOGStaticMemoryGadget { let opcode = cb.query_cell(); // Query address by a full word - let address = cb.query_word(); + let address = cb.query_word_rlc(); // Check if this is an MSTORE8 let is_mstore8 = IsEqualGadget::construct(cb, opcode.expr(), OpcodeId::MSTORE8.expr()); diff --git a/zkevm-circuits/src/evm_circuit/execution/exp.rs b/zkevm-circuits/src/evm_circuit/execution/exp.rs index 7da87a7e97..91089295a0 100644 --- a/zkevm-circuits/src/evm_circuit/execution/exp.rs +++ b/zkevm-circuits/src/evm_circuit/execution/exp.rs @@ -53,9 +53,9 @@ impl ExecutionGadget for ExponentiationGadget { // Query RLC-encoded values for base, exponent and exponentiation, where: // base^exponent == exponentiation (mod 2^256). - let base_rlc = cb.query_rlc(); - let exponent_rlc = cb.query_rlc(); - let exponentiation_rlc = cb.query_rlc(); + let base_rlc = cb.query_word_rlc(); + let exponent_rlc = cb.query_word_rlc(); + let exponentiation_rlc = cb.query_word_rlc(); // Pop RLC-encoded base and exponent from the stack. cb.stack_pop(base_rlc.expr()); @@ -90,12 +90,12 @@ impl ExecutionGadget for ExponentiationGadget { let exponent_is_one_expr = and::expr([exponent_lo_is_one.expr(), exponent_hi_is_zero.expr()]); - let zero_rlc = cb.query_word(); + let zero_rlc = cb.query_word_rlc(); cb.require_zero( "base * base + c == base^2 (c == 0)", sum::expr(&zero_rlc.cells), ); - let base_sq = cb.query_word(); + let base_sq = cb.query_word_rlc(); // If exponent == 0, base^exponent == 1, which implies: // 1. Low bytes of exponentiation == 1 diff --git a/zkevm-circuits/src/evm_circuit/execution/extcodehash.rs b/zkevm-circuits/src/evm_circuit/execution/extcodehash.rs index a6ab37bb69..18a08a6a37 100644 --- a/zkevm-circuits/src/evm_circuit/execution/extcodehash.rs +++ b/zkevm-circuits/src/evm_circuit/execution/extcodehash.rs @@ -19,7 +19,6 @@ use crate::{ }; use eth_types::{evm_types::GasCost, Field, ToLittleEndian}; use halo2_proofs::{circuit::Value, plonk::Error}; -use keccak256::EMPTY_HASH_LE; #[derive(Clone, Debug)] pub(crate) struct ExtcodehashGadget { @@ -40,7 +39,7 @@ impl ExecutionGadget for ExtcodehashGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::EXTCODEHASH; fn configure(cb: &mut ConstraintBuilder) -> Self { - let address_word = cb.query_word(); + let address_word = cb.query_word_rlc(); let address = from_bytes::expr(&address_word.cells[..N_BYTES_ACCOUNT_ADDRESS]); cb.stack_pop(address_word.expr()); @@ -63,10 +62,6 @@ impl ExecutionGadget for ExtcodehashGadget { let code_hash = cb.query_cell(); cb.account_read(address, AccountFieldTag::CodeHash, code_hash.expr()); - let empty_code_hash_rlc = Word::random_linear_combine_expr( - (*EMPTY_HASH_LE).map(|byte| byte.expr()), - cb.power_of_randomness(), - ); // Note that balance is RLC encoded, but RLC(x) = 0 iff x = 0, so we don't need // go to the work of writing out the RLC expression let is_empty = BatchedIsZeroGadget::construct( @@ -74,7 +69,7 @@ impl ExecutionGadget for ExtcodehashGadget { [ nonce.expr(), balance.expr(), - code_hash.expr() - empty_code_hash_rlc, + code_hash.expr() - cb.empty_hash_rlc(), ], ); @@ -143,20 +138,18 @@ impl ExecutionGadget for ExtcodehashGadget { let [nonce, balance, code_hash] = [5, 6, 7].map(|i| { block.rws[step.rw_indices[i]] - .table_assignment_aux(block.randomness) + .table_assignment(region.challenges().evm_word()) .value }); - self.nonce.assign(region, offset, Value::known(nonce))?; - self.balance.assign(region, offset, Value::known(balance))?; - self.code_hash - .assign(region, offset, Value::known(code_hash))?; + self.nonce.assign(region, offset, nonce)?; + self.balance.assign(region, offset, balance)?; + self.code_hash.assign(region, offset, code_hash)?; - let empty_code_hash_rlc = Word::random_linear_combine(*EMPTY_HASH_LE, block.randomness); - self.is_empty.assign( + self.is_empty.assign_value( region, offset, - [nonce, balance, code_hash - empty_code_hash_rlc], + [nonce, balance, code_hash - region.empty_hash_rlc()], )?; Ok(()) diff --git a/zkevm-circuits/src/evm_circuit/execution/extcodesize.rs b/zkevm-circuits/src/evm_circuit/execution/extcodesize.rs index 31929f290c..39a503d7c2 100644 --- a/zkevm-circuits/src/evm_circuit/execution/extcodesize.rs +++ b/zkevm-circuits/src/evm_circuit/execution/extcodesize.rs @@ -6,9 +6,7 @@ use crate::evm_circuit::util::constraint_builder::Transition::Delta; use crate::evm_circuit::util::constraint_builder::{ ConstraintBuilder, ReversionInfo, StepStateTransition, }; -use crate::evm_circuit::util::{ - from_bytes, select, CachedRegion, Cell, RandomLinearCombination, Word, -}; +use crate::evm_circuit::util::{from_bytes, select, CachedRegion, Cell, Word}; use crate::evm_circuit::witness::{Block, Call, ExecStep, Rw, Transaction}; use crate::table::{AccountFieldTag, CallContextFieldTag}; use crate::util::Expr; @@ -37,7 +35,7 @@ impl ExecutionGadget for ExtcodesizeGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::EXTCODESIZE; fn configure(cb: &mut ConstraintBuilder) -> Self { - let address_word = cb.query_word(); + let address_word = cb.query_word_rlc(); let address = from_bytes::expr(&address_word.cells[..N_BYTES_ACCOUNT_ADDRESS]); cb.stack_pop(address_word.expr()); @@ -68,13 +66,9 @@ impl ExecutionGadget for ExtcodesizeGadget { from_bytes::expr(&code_size_bytes), code_size.expr(), ); - cb.stack_push(select::expr( exists.expr(), - RandomLinearCombination::random_linear_combine_expr( - code_size_bytes.clone().map(|c| c.expr()), - cb.power_of_randomness(), - ), + cb.word_rlc(code_size_bytes.clone().map(|c| c.expr())), 0.expr(), )); @@ -155,14 +149,8 @@ impl ExecutionGadget for ExtcodesizeGadget { self.exists .assign(region, offset, Value::known(F::from(exists)))?; - self.code_hash.assign( - region, - offset, - Value::known(RandomLinearCombination::random_linear_combine( - code_hash.to_le_bytes(), - block.randomness, - )), - )?; + self.code_hash + .assign(region, offset, region.word_rlc(code_hash))?; self.code_size .assign(region, offset, Value::known(F::from(code_size)))?; for (c, b) in self diff --git a/zkevm-circuits/src/evm_circuit/execution/gas.rs b/zkevm-circuits/src/evm_circuit/execution/gas.rs index f70d95ef84..7d06f132ca 100644 --- a/zkevm-circuits/src/evm_circuit/execution/gas.rs +++ b/zkevm-circuits/src/evm_circuit/execution/gas.rs @@ -28,7 +28,7 @@ impl ExecutionGadget for GasGadget { fn configure(cb: &mut ConstraintBuilder) -> Self { // The gas passed to a transaction is a 64-bit number. - let gas_left = cb.query_rlc(); + let gas_left = cb.query_word_rlc(); // The `gas_left` in the current state has to be deducted by the gas // used by the `GAS` opcode itself. diff --git a/zkevm-circuits/src/evm_circuit/execution/gasprice.rs b/zkevm-circuits/src/evm_circuit/execution/gasprice.rs index db44d07781..95f5e44dd8 100644 --- a/zkevm-circuits/src/evm_circuit/execution/gasprice.rs +++ b/zkevm-circuits/src/evm_circuit/execution/gasprice.rs @@ -5,7 +5,7 @@ use crate::{ util::{ common_gadget::SameContextGadget, constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, - CachedRegion, Cell, Word, + CachedRegion, Cell, }, witness::{Block, Call, ExecStep, Transaction}, }, @@ -13,7 +13,7 @@ use crate::{ util::Expr, }; use bus_mapping::evm::OpcodeId; -use eth_types::{Field, ToLittleEndian}; +use eth_types::Field; use halo2_proofs::{circuit::Value, plonk::Error}; #[derive(Clone, Debug)] @@ -77,14 +77,8 @@ impl ExecutionGadget for GasPriceGadget { self.tx_id .assign(region, offset, Value::known(F::from(tx.id as u64)))?; - self.gas_price.assign( - region, - offset, - Value::known(Word::random_linear_combine( - gas_price.to_le_bytes(), - block.randomness, - )), - )?; + self.gas_price + .assign(region, offset, region.word_rlc(gas_price))?; self.same_context.assign_exec_step(region, offset, step)?; diff --git a/zkevm-circuits/src/evm_circuit/execution/is_zero.rs b/zkevm-circuits/src/evm_circuit/execution/is_zero.rs index bbc1efc2fc..b07f02cb07 100644 --- a/zkevm-circuits/src/evm_circuit/execution/is_zero.rs +++ b/zkevm-circuits/src/evm_circuit/execution/is_zero.rs @@ -5,15 +5,15 @@ use crate::{ util::{ common_gadget::SameContextGadget, constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, - math_gadget, CachedRegion, Cell, Word, + math_gadget, CachedRegion, Cell, }, witness::{Block, Call, ExecStep, Transaction}, }, util::Expr, }; use bus_mapping::evm::OpcodeId; -use eth_types::{Field, ToLittleEndian}; -use halo2_proofs::{circuit::Value, plonk::Error}; +use eth_types::Field; +use halo2_proofs::plonk::Error; #[derive(Clone, Debug)] pub(crate) struct IsZeroGadget { @@ -65,9 +65,9 @@ impl ExecutionGadget for IsZeroGadget { self.same_context.assign_exec_step(region, offset, step)?; let value = block.rws[step.rw_indices[0]].stack_value(); - let value = Word::random_linear_combine(value.to_le_bytes(), block.randomness); - self.value.assign(region, offset, Value::known(value))?; - self.is_zero.assign(region, offset, value)?; + let value = region.word_rlc(value); + self.value.assign(region, offset, value)?; + self.is_zero.assign_value(region, offset, value)?; Ok(()) } diff --git a/zkevm-circuits/src/evm_circuit/execution/jump.rs b/zkevm-circuits/src/evm_circuit/execution/jump.rs index 7e95adb79b..9d60f47fc4 100644 --- a/zkevm-circuits/src/evm_circuit/execution/jump.rs +++ b/zkevm-circuits/src/evm_circuit/execution/jump.rs @@ -30,7 +30,7 @@ impl ExecutionGadget for JumpGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::JUMP; fn configure(cb: &mut ConstraintBuilder) -> Self { - let destination = cb.query_rlc(); + let destination = cb.query_word_rlc(); // Pop the value from the stack cb.stack_pop(destination.expr()); diff --git a/zkevm-circuits/src/evm_circuit/execution/jumpi.rs b/zkevm-circuits/src/evm_circuit/execution/jumpi.rs index 56145e66f5..7e4a8cbb36 100644 --- a/zkevm-circuits/src/evm_circuit/execution/jumpi.rs +++ b/zkevm-circuits/src/evm_circuit/execution/jumpi.rs @@ -11,20 +11,20 @@ use crate::{ }, from_bytes, math_gadget::IsZeroGadget, - select, CachedRegion, Cell, RandomLinearCombination, Word, + select, CachedRegion, Cell, CellType, RandomLinearCombination, }, witness::{Block, Call, ExecStep, Transaction}, }, util::Expr, }; use eth_types::{evm_types::OpcodeId, Field, ToLittleEndian}; -use halo2_proofs::{circuit::Value, plonk::Error}; +use halo2_proofs::plonk::Error; #[derive(Clone, Debug)] pub(crate) struct JumpiGadget { same_context: SameContextGadget, destination: RandomLinearCombination, - condition: Cell, + phase2_condition: Cell, is_condition_zero: IsZeroGadget, } @@ -34,15 +34,15 @@ impl ExecutionGadget for JumpiGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::JUMPI; fn configure(cb: &mut ConstraintBuilder) -> Self { - let destination = cb.query_rlc(); - let condition = cb.query_cell(); + let destination = cb.query_word_rlc(); + let phase2_condition = cb.query_cell_with_type(CellType::StoragePhase2); // Pop the value from the stack cb.stack_pop(destination.expr()); - cb.stack_pop(condition.expr()); + cb.stack_pop(phase2_condition.expr()); // Determine if the jump condition is met - let is_condition_zero = IsZeroGadget::construct(cb, condition.expr()); + let is_condition_zero = IsZeroGadget::construct(cb, phase2_condition.expr()); let should_jump = 1.expr() - is_condition_zero.expr(); // Lookup opcode at destination when should_jump @@ -76,7 +76,7 @@ impl ExecutionGadget for JumpiGadget { Self { same_context, destination, - condition, + phase2_condition, is_condition_zero, } } @@ -94,7 +94,7 @@ impl ExecutionGadget for JumpiGadget { let [destination, condition] = [step.rw_indices[0], step.rw_indices[1]].map(|idx| block.rws[idx].stack_value()); - let condition = Word::random_linear_combine(condition.to_le_bytes(), block.randomness); + let condition = region.word_rlc(condition); self.destination.assign( region, @@ -105,9 +105,9 @@ impl ExecutionGadget for JumpiGadget { .unwrap(), ), )?; - self.condition - .assign(region, offset, Value::known(condition))?; - self.is_condition_zero.assign(region, offset, condition)?; + self.phase2_condition.assign(region, offset, condition)?; + self.is_condition_zero + .assign_value(region, offset, condition)?; Ok(()) } diff --git a/zkevm-circuits/src/evm_circuit/execution/logs.rs b/zkevm-circuits/src/evm_circuit/execution/logs.rs index 86e675d277..a4d7c79e10 100644 --- a/zkevm-circuits/src/evm_circuit/execution/logs.rs +++ b/zkevm-circuits/src/evm_circuit/execution/logs.rs @@ -10,7 +10,7 @@ use crate::{ Transition::{Delta, To}, }, memory_gadget::{MemoryAddressGadget, MemoryExpansionGadget}, - not, sum, CachedRegion, Cell, Word, + not, sum, CachedRegion, Cell, CellType, }, witness::{Block, Call, ExecStep, Transaction}, }, @@ -19,7 +19,7 @@ use crate::{ }; use array_init::array_init; use bus_mapping::circuit_input_builder::CopyDataType; -use eth_types::{evm_types::GasCost, evm_types::OpcodeId, ToLittleEndian, ToScalar}; +use eth_types::{evm_types::GasCost, evm_types::OpcodeId, ToScalar}; use eth_types::{Field, U256}; use halo2_proofs::{circuit::Value, plonk::Error}; @@ -28,7 +28,7 @@ pub(crate) struct LogGadget { same_context: SameContextGadget, // memory address memory_address: MemoryAddressGadget, - topics: [Cell; 4], + phase2_topics: [Cell; 4], topic_selectors: [Cell; 4], contract_address: Cell, @@ -46,7 +46,7 @@ impl ExecutionGadget for LogGadget { fn configure(cb: &mut ConstraintBuilder) -> Self { let mstart = cb.query_cell(); - let msize = cb.query_rlc(); + let msize = cb.query_word_rlc(); // Pop mstart_address, msize from stack cb.stack_pop(mstart.expr()); @@ -74,9 +74,9 @@ impl ExecutionGadget for LogGadget { }); // constrain topics in logs - let topics = array_init(|_| cb.query_cell()); + let phase2_topics = array_init(|_| cb.query_cell_with_type(CellType::StoragePhase2)); let topic_selectors: [Cell; 4] = array_init(|_| cb.query_cell()); - for (idx, topic) in topics.iter().enumerate() { + for (idx, topic) in phase2_topics.iter().enumerate() { cb.condition(topic_selectors[idx].expr(), |cb| { cb.stack_pop(topic.expr()); }); @@ -170,7 +170,7 @@ impl ExecutionGadget for LogGadget { Self { same_context, memory_address, - topics, + phase2_topics, topic_selectors, contract_address, is_static_call, @@ -195,9 +195,9 @@ impl ExecutionGadget for LogGadget { let [memory_start, msize] = [step.rw_indices[0], step.rw_indices[1]].map(|idx| block.rws[idx].stack_value()); - let memory_address = - self.memory_address - .assign(region, offset, memory_start, msize, block.randomness)?; + let memory_address = self + .memory_address + .assign(region, offset, memory_start, msize)?; // Memory expansion self.memory_expansion @@ -216,18 +216,15 @@ impl ExecutionGadget for LogGadget { }; for i in 0..4 { - let mut topic = Word::random_linear_combine([0; 32], block.randomness); + let mut topic = region.word_rlc(U256::zero()); if i < topic_count { - topic = Word::random_linear_combine( - block.rws[topic_stack_entry].stack_value().to_le_bytes(), - block.randomness, - ); + topic = region.word_rlc(block.rws[topic_stack_entry].stack_value()); self.topic_selectors[i].assign(region, offset, Value::known(F::one()))?; topic_stack_entry.1 += 1; } else { self.topic_selectors[i].assign(region, offset, Value::known(F::zero()))?; } - self.topics[i].assign(region, offset, Value::known(topic))?; + self.phase2_topics[i].assign(region, offset, topic)?; } self.contract_address.assign( diff --git a/zkevm-circuits/src/evm_circuit/execution/memory.rs b/zkevm-circuits/src/evm_circuit/execution/memory.rs index 8da763f35c..a48180af16 100644 --- a/zkevm-circuits/src/evm_circuit/execution/memory.rs +++ b/zkevm-circuits/src/evm_circuit/execution/memory.rs @@ -40,8 +40,8 @@ impl ExecutionGadget for MemoryGadget { let opcode = cb.query_cell(); // In successful case the address must be in 5 bytes - let address = cb.query_rlc(); - let value = cb.query_word(); + let address = cb.query_word_rlc(); + let value = cb.query_word_rlc(); // Check if this is an MLOAD let is_mload = IsEqualGadget::construct(cb, opcode.expr(), OpcodeId::MLOAD.expr()); diff --git a/zkevm-circuits/src/evm_circuit/execution/msize.rs b/zkevm-circuits/src/evm_circuit/execution/msize.rs index ebbe8450d4..b587d9791b 100644 --- a/zkevm-circuits/src/evm_circuit/execution/msize.rs +++ b/zkevm-circuits/src/evm_circuit/execution/msize.rs @@ -28,7 +28,7 @@ impl ExecutionGadget for MsizeGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::MSIZE; fn configure(cb: &mut ConstraintBuilder) -> Self { - let value = cb.query_rlc(); + let value = cb.query_word_rlc(); // memory_size is limited to 64 bits so we only consider 8 bytes cb.require_equal( 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 4b2384a624..404c6acd16 100644 --- a/zkevm-circuits/src/evm_circuit/execution/mul_div_mod.rs +++ b/zkevm-circuits/src/evm_circuit/execution/mul_div_mod.rs @@ -52,10 +52,10 @@ impl ExecutionGadget for MulDivModGadget { let is_mod = (opcode.expr() - OpcodeId::MUL.expr()) * (opcode.expr() - OpcodeId::DIV.expr()) * F::from(8).invert().unwrap(); - let a = cb.query_word(); - let b = cb.query_word(); - let c = cb.query_word(); - let d = cb.query_word(); + let a = cb.query_word_rlc(); + let b = cb.query_word_rlc(); + let c = cb.query_word_rlc(); + let d = cb.query_word_rlc(); let mul_add_words = MulAddWordsGadget::construct(cb, [&a, &b, &c, &d]); let divisor_is_zero = IsZeroGadget::construct(cb, sum::expr(&b.cells)); diff --git a/zkevm-circuits/src/evm_circuit/execution/mulmod.rs b/zkevm-circuits/src/evm_circuit/execution/mulmod.rs index 8f451d7a4e..4f2242df54 100644 --- a/zkevm-circuits/src/evm_circuit/execution/mulmod.rs +++ b/zkevm-circuits/src/evm_circuit/execution/mulmod.rs @@ -44,16 +44,16 @@ impl ExecutionGadget for MulModGadget { fn configure(cb: &mut ConstraintBuilder) -> Self { let opcode = cb.query_cell(); - let a = cb.query_word(); - let b = cb.query_word(); - let n = cb.query_word(); - let r = cb.query_word(); + let a = cb.query_word_rlc(); + let b = cb.query_word_rlc(); + let n = cb.query_word_rlc(); + let r = cb.query_word_rlc(); - let k = cb.query_word(); + let k = cb.query_word_rlc(); - let a_reduced = cb.query_word(); - let d = cb.query_word(); - let e = cb.query_word(); + let a_reduced = cb.query_word_rlc(); + let d = cb.query_word_rlc(); + let e = cb.query_word_rlc(); // 1. k1 * n + a_reduced == a let modword = ModGadget::construct(cb, [&a, &n, &a_reduced]); @@ -147,8 +147,7 @@ impl ExecutionGadget for MulModGadget { self.d.assign(region, offset, Some(d.to_le_bytes()))?; self.e.assign(region, offset, Some(e.to_le_bytes()))?; - self.modword - .assign(region, offset, a, n, a_reduced, k1, block.randomness)?; + self.modword.assign(region, offset, a, n, a_reduced, k1)?; self.mul512_left .assign(region, offset, [a_reduced, b, d, e], None)?; self.mul512_right diff --git a/zkevm-circuits/src/evm_circuit/execution/not.rs b/zkevm-circuits/src/evm_circuit/execution/not.rs index c90d0f5130..1d12c42820 100644 --- a/zkevm-circuits/src/evm_circuit/execution/not.rs +++ b/zkevm-circuits/src/evm_circuit/execution/not.rs @@ -31,8 +31,8 @@ impl ExecutionGadget for NotGadget { fn configure(cb: &mut ConstraintBuilder) -> Self { let opcode = cb.query_cell(); - let input = cb.query_word(); - let output = cb.query_word(); + let input = cb.query_word_rlc(); + let output = cb.query_word_rlc(); cb.stack_pop(input.expr()); cb.stack_push(output.expr()); diff --git a/zkevm-circuits/src/evm_circuit/execution/origin.rs b/zkevm-circuits/src/evm_circuit/execution/origin.rs index 9fb45b00b0..8694dda9f0 100644 --- a/zkevm-circuits/src/evm_circuit/execution/origin.rs +++ b/zkevm-circuits/src/evm_circuit/execution/origin.rs @@ -30,7 +30,7 @@ impl ExecutionGadget for OriginGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::ORIGIN; fn configure(cb: &mut ConstraintBuilder) -> Self { - let origin = cb.query_rlc::(); + let origin = cb.query_word_rlc::(); // Lookup in call_ctx the TxId let tx_id = cb.call_context(None, CallContextFieldTag::TxId); diff --git a/zkevm-circuits/src/evm_circuit/execution/pc.rs b/zkevm-circuits/src/evm_circuit/execution/pc.rs index 27b16e2e02..c52083ed1b 100644 --- a/zkevm-circuits/src/evm_circuit/execution/pc.rs +++ b/zkevm-circuits/src/evm_circuit/execution/pc.rs @@ -28,7 +28,7 @@ impl ExecutionGadget for PcGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::PC; fn configure(cb: &mut ConstraintBuilder) -> Self { - let value = cb.query_rlc(); + let value = cb.query_word_rlc(); // program_counter is limited to 64 bits so we only consider 8 bytes cb.require_equal( diff --git a/zkevm-circuits/src/evm_circuit/execution/pop.rs b/zkevm-circuits/src/evm_circuit/execution/pop.rs index 8fe37f4f71..22f997f20e 100644 --- a/zkevm-circuits/src/evm_circuit/execution/pop.rs +++ b/zkevm-circuits/src/evm_circuit/execution/pop.rs @@ -5,20 +5,20 @@ use crate::{ util::{ common_gadget::SameContextGadget, constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, - CachedRegion, Cell, Word, + CachedRegion, Cell, CellType, }, witness::{Block, Call, ExecStep, Transaction}, }, util::Expr, }; use bus_mapping::evm::OpcodeId; -use eth_types::{Field, ToLittleEndian}; -use halo2_proofs::{circuit::Value, plonk::Error}; +use eth_types::Field; +use halo2_proofs::plonk::Error; #[derive(Clone, Debug)] pub(crate) struct PopGadget { same_context: SameContextGadget, - value: Cell, + phase2_value: Cell, } impl ExecutionGadget for PopGadget { @@ -27,10 +27,10 @@ impl ExecutionGadget for PopGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::POP; fn configure(cb: &mut ConstraintBuilder) -> Self { - let value = cb.query_cell(); + let phase2_value = cb.query_cell_with_type(CellType::StoragePhase2); // Pop the value from the stack - cb.stack_pop(value.expr()); + cb.stack_pop(phase2_value.expr()); // State transition let step_state_transition = StepStateTransition { @@ -45,7 +45,7 @@ impl ExecutionGadget for PopGadget { Self { same_context, - value, + phase2_value, } } @@ -61,14 +61,8 @@ impl ExecutionGadget for PopGadget { self.same_context.assign_exec_step(region, offset, step)?; let value = block.rws[step.rw_indices[0]].stack_value(); - self.value.assign( - region, - offset, - Value::known(Word::random_linear_combine( - value.to_le_bytes(), - block.randomness, - )), - )?; + self.phase2_value + .assign(region, offset, region.word_rlc(value))?; Ok(()) } diff --git a/zkevm-circuits/src/evm_circuit/execution/push.rs b/zkevm-circuits/src/evm_circuit/execution/push.rs index d75ebd5a77..5f6596cbb0 100644 --- a/zkevm-circuits/src/evm_circuit/execution/push.rs +++ b/zkevm-circuits/src/evm_circuit/execution/push.rs @@ -30,7 +30,7 @@ impl ExecutionGadget for PushGadget { fn configure(cb: &mut ConstraintBuilder) -> Self { let opcode = cb.query_cell(); - let value = cb.query_rlc(); + let value = cb.query_word_rlc(); // Query selectors for each opcode_lookup let selectors = array_init(|_| cb.query_bool()); diff --git a/zkevm-circuits/src/evm_circuit/execution/return_revert.rs b/zkevm-circuits/src/evm_circuit/execution/return_revert.rs index d123c338a1..5aae53e5f2 100644 --- a/zkevm-circuits/src/evm_circuit/execution/return_revert.rs +++ b/zkevm-circuits/src/evm_circuit/execution/return_revert.rs @@ -11,7 +11,7 @@ use crate::{ }, math_gadget::{IsZeroGadget, MinMaxGadget}, memory_gadget::{MemoryAddressGadget, MemoryExpansionGadget}, - not, CachedRegion, Cell, RandomLinearCombination, Word, + not, CachedRegion, Cell, }, witness::{Block, Call, ExecStep, Transaction}, }, @@ -19,10 +19,9 @@ use crate::{ util::Expr, }; use bus_mapping::{circuit_input_builder::CopyDataType, evm::OpcodeId}; -use eth_types::{Field, ToScalar}; +use eth_types::{Field, ToScalar, U256}; use ethers_core::utils::keccak256; use halo2_proofs::{circuit::Value, plonk::Error}; -use keccak256::EMPTY_HASH_LE; #[derive(Clone, Debug)] pub(crate) struct ReturnRevertGadget { @@ -58,7 +57,7 @@ impl ExecutionGadget for ReturnRevertGadget { cb.opcode_lookup(opcode.expr(), 1.expr()); let offset = cb.query_cell(); - let length = cb.query_rlc(); + let length = cb.query_word_rlc(); cb.stack_pop(offset.expr()); cb.stack_pop(length.expr()); let range = MemoryAddressGadget::construct(cb, offset, length); @@ -121,16 +120,11 @@ impl ExecutionGadget for ReturnRevertGadget { .map(|tag| cb.call_context(None, tag)); let mut reversion_info = cb.reversion_info_read(None); - let empty_code_hash_rlc = Word::random_linear_combine_expr( - (*EMPTY_HASH_LE).map(|byte| byte.expr()), - cb.power_of_randomness(), - ); - cb.account_write( address.expr(), AccountFieldTag::CodeHash, code_hash.expr(), - empty_code_hash_rlc, + cb.empty_hash_rlc(), Some(&mut reversion_info), ); @@ -256,9 +250,7 @@ impl ExecutionGadget for ReturnRevertGadget { )?; let [memory_offset, length] = [0, 1].map(|i| block.rws[step.rw_indices[i]].stack_value()); - let range = self - .range - .assign(region, offset, memory_offset, length, block.randomness)?; + let range = self.range.assign(region, offset, memory_offset, length)?; self.memory_expansion .assign(region, offset, step.memory_word_size(), [range])?; @@ -290,10 +282,7 @@ impl ExecutionGadget for ReturnRevertGadget { self.code_hash.assign( region, offset, - Value::known(RandomLinearCombination::random_linear_combine( - code_hash, - block.randomness, - )), + region.word_rlc(U256::from_little_endian(&code_hash)), )?; } diff --git a/zkevm-circuits/src/evm_circuit/execution/returndatacopy.rs b/zkevm-circuits/src/evm_circuit/execution/returndatacopy.rs index 274e0f0bfa..e046796b39 100644 --- a/zkevm-circuits/src/evm_circuit/execution/returndatacopy.rs +++ b/zkevm-circuits/src/evm_circuit/execution/returndatacopy.rs @@ -61,8 +61,8 @@ impl ExecutionGadget for ReturnDataCopyGadget { let opcode = cb.query_cell(); let dest_offset = cb.query_cell(); - let data_offset = cb.query_rlc(); - let size = cb.query_rlc(); + let data_offset = cb.query_word_rlc(); + let size = cb.query_word_rlc(); // 1. Pop dest_offset, offset, length from stack cb.stack_pop(dest_offset.expr()); @@ -227,9 +227,9 @@ impl ExecutionGadget for ReturnDataCopyGadget { )?; // assign the destination memory offset. - let memory_address = - self.dst_memory_addr - .assign(region, offset, dest_offset, size, block.randomness)?; + let memory_address = self + .dst_memory_addr + .assign(region, offset, dest_offset, size)?; // assign to gadgets handling memory expansion cost and copying cost. let (_, memory_expansion_cost) = self.memory_expansion.assign( diff --git a/zkevm-circuits/src/evm_circuit/execution/returndatasize.rs b/zkevm-circuits/src/evm_circuit/execution/returndatasize.rs index 9d0732a23f..24a1ceb967 100644 --- a/zkevm-circuits/src/evm_circuit/execution/returndatasize.rs +++ b/zkevm-circuits/src/evm_circuit/execution/returndatasize.rs @@ -32,7 +32,7 @@ impl ExecutionGadget for ReturnDataSizeGadget { let opcode = cb.query_cell(); // Add lookup constraint in the call context for the returndatasize field. - let return_data_size = cb.query_rlc(); + let return_data_size = cb.query_word_rlc(); cb.call_context_lookup( false.expr(), None, diff --git a/zkevm-circuits/src/evm_circuit/execution/selfbalance.rs b/zkevm-circuits/src/evm_circuit/execution/selfbalance.rs index f8ea807303..2d366afd27 100644 --- a/zkevm-circuits/src/evm_circuit/execution/selfbalance.rs +++ b/zkevm-circuits/src/evm_circuit/execution/selfbalance.rs @@ -5,7 +5,7 @@ use crate::{ util::{ common_gadget::SameContextGadget, constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, - CachedRegion, Cell, Word, + CachedRegion, Cell, CellType, }, witness::{Block, Call, ExecStep, Transaction}, }, @@ -13,14 +13,14 @@ use crate::{ util::Expr, }; use bus_mapping::evm::OpcodeId; -use eth_types::{Field, ToLittleEndian, ToScalar}; +use eth_types::{Field, ToScalar}; use halo2_proofs::{circuit::Value, plonk::Error}; #[derive(Clone, Debug)] pub(crate) struct SelfbalanceGadget { same_context: SameContextGadget, callee_address: Cell, - self_balance: Cell, + phase2_self_balance: Cell, } impl ExecutionGadget for SelfbalanceGadget { @@ -31,14 +31,14 @@ impl ExecutionGadget for SelfbalanceGadget { fn configure(cb: &mut ConstraintBuilder) -> Self { let callee_address = cb.call_context(None, CallContextFieldTag::CalleeAddress); - let self_balance = cb.query_cell(); + let phase2_self_balance = cb.query_cell_with_type(CellType::StoragePhase2); cb.account_read( callee_address.expr(), AccountFieldTag::Balance, - self_balance.expr(), + phase2_self_balance.expr(), ); - cb.stack_push(self_balance.expr()); + cb.stack_push(phase2_self_balance.expr()); let opcode = cb.query_cell(); let step_state_transition = StepStateTransition { @@ -52,7 +52,7 @@ impl ExecutionGadget for SelfbalanceGadget { Self { same_context, - self_balance, + phase2_self_balance, callee_address, } } @@ -79,14 +79,8 @@ impl ExecutionGadget for SelfbalanceGadget { )?; let self_balance = block.rws[step.rw_indices[2]].stack_value(); - self.self_balance.assign( - region, - offset, - Value::known(Word::random_linear_combine( - self_balance.to_le_bytes(), - block.randomness, - )), - )?; + self.phase2_self_balance + .assign(region, offset, region.word_rlc(self_balance))?; Ok(()) } diff --git a/zkevm-circuits/src/evm_circuit/execution/sha3.rs b/zkevm-circuits/src/evm_circuit/execution/sha3.rs index 2b09155c13..581f559707 100644 --- a/zkevm-circuits/src/evm_circuit/execution/sha3.rs +++ b/zkevm-circuits/src/evm_circuit/execution/sha3.rs @@ -37,8 +37,8 @@ impl ExecutionGadget for Sha3Gadget { let opcode = cb.query_cell(); let offset = cb.query_cell(); - let size = cb.query_rlc(); - let sha3_rlc = cb.query_rlc(); + let size = cb.query_word_rlc(); + let sha3_rlc = cb.query_word_rlc(); cb.stack_pop(offset.expr()); cb.stack_pop(size.expr()); @@ -48,6 +48,7 @@ impl ExecutionGadget for Sha3Gadget { let copy_rwc_inc = cb.query_cell(); let rlc_acc = cb.query_cell(); + cb.condition(memory_address.has_length(), |cb| { cb.copy_table_lookup( cb.curr.state.call_id.expr(), @@ -62,6 +63,7 @@ impl ExecutionGadget for Sha3Gadget { copy_rwc_inc.expr(), ); }); + cb.condition(not::expr(memory_address.has_length()), |cb| { cb.require_zero("copy_rwc_inc == 0 for size = 0", copy_rwc_inc.expr()); cb.require_zero("rlc_acc == 0 for size = 0", rlc_acc.expr()); @@ -112,9 +114,9 @@ impl ExecutionGadget for Sha3Gadget { let [memory_offset, size, sha3_output] = [step.rw_indices[0], step.rw_indices[1], step.rw_indices[2]] .map(|idx| block.rws[idx].stack_value()); - let memory_address = - self.memory_address - .assign(region, offset, memory_offset, size, block.randomness)?; + let memory_address = self + .memory_address + .assign(region, offset, memory_offset, size)?; self.sha3_rlc .assign(region, offset, Some(sha3_output.to_le_bytes()))?; @@ -130,8 +132,12 @@ impl ExecutionGadget for Sha3Gadget { let values: Vec = (3..3 + (size.low_u64() as usize)) .map(|i| block.rws[step.rw_indices[i]].memory_value()) .collect(); - let rlc_acc = rlc::value(values.iter().rev(), block.randomness); - self.rlc_acc.assign(region, offset, Value::known(rlc_acc))?; + + let rlc_acc = region + .challenges() + .keccak_input() + .map(|randomness| rlc::value(values.iter().rev(), randomness)); + self.rlc_acc.assign(region, offset, rlc_acc)?; // Memory expansion and dynamic gas cost for reading it. let (_, memory_expansion_gas_cost) = self.memory_expansion.assign( diff --git a/zkevm-circuits/src/evm_circuit/execution/shl_shr.rs b/zkevm-circuits/src/evm_circuit/execution/shl_shr.rs index b5dc703f95..551af565e0 100644 --- a/zkevm-circuits/src/evm_circuit/execution/shl_shr.rs +++ b/zkevm-circuits/src/evm_circuit/execution/shl_shr.rs @@ -54,11 +54,11 @@ impl ExecutionGadget for ShlShrGadget { let is_shl = OpcodeId::SHR.expr() - opcode.expr(); let is_shr = 1.expr() - is_shl.expr(); - let quotient = cb.query_word(); - let divisor = cb.query_word(); - let remainder = cb.query_word(); - let dividend = cb.query_word(); - let shift = cb.query_word(); + let quotient = cb.query_word_rlc(); + let divisor = cb.query_word_rlc(); + let remainder = cb.query_word_rlc(); + let dividend = cb.query_word_rlc(); + let shift = cb.query_word_rlc(); let shf0 = cb.query_cell(); let mul_add_words = diff --git a/zkevm-circuits/src/evm_circuit/execution/signed_comparator.rs b/zkevm-circuits/src/evm_circuit/execution/signed_comparator.rs index 46ea013bcb..e78898fc78 100644 --- a/zkevm-circuits/src/evm_circuit/execution/signed_comparator.rs +++ b/zkevm-circuits/src/evm_circuit/execution/signed_comparator.rs @@ -42,8 +42,8 @@ impl ExecutionGadget for SignedComparatorGadget { fn configure(cb: &mut ConstraintBuilder) -> Self { let opcode = cb.query_cell(); - let a = cb.query_word(); - let b = cb.query_word(); + let a = cb.query_word_rlc(); + let b = cb.query_word_rlc(); // The Signed Comparator gadget is used for both opcodes SLT and SGT. // Depending on whether the opcode is SLT or SGT, we diff --git a/zkevm-circuits/src/evm_circuit/execution/signextend.rs b/zkevm-circuits/src/evm_circuit/execution/signextend.rs index b5af6fdd93..ba670c8c60 100644 --- a/zkevm-circuits/src/evm_circuit/execution/signextend.rs +++ b/zkevm-circuits/src/evm_circuit/execution/signextend.rs @@ -17,7 +17,10 @@ use crate::{ use array_init::array_init; use bus_mapping::evm::OpcodeId; use eth_types::{Field, ToLittleEndian}; -use halo2_proofs::{circuit::Value, plonk::Error}; +use halo2_proofs::{ + circuit::Value, + plonk::{Error, Expression}, +}; #[derive(Clone, Debug)] pub(crate) struct SignextendGadget { @@ -36,8 +39,8 @@ impl ExecutionGadget for SignextendGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::SIGNEXTEND; fn configure(cb: &mut ConstraintBuilder) -> Self { - let index = cb.query_word(); - let value = cb.query_word(); + let index = cb.query_word_rlc(); + let value = cb.query_word_rlc(); let sign_byte = cb.query_cell(); let selectors = array_init(|_| cb.query_bool()); @@ -108,6 +111,8 @@ impl ExecutionGadget for SignextendGadget { // enabled need to be changed to the sign byte. // When a byte was selected all the **following** bytes need to be // replaced (hence the `selectors[idx - 1]`). + let powers_of_randomness: [Expression; 31] = + cb.challenges().evm_word_powers_of_randomness(); let result = Word::random_linear_combine_expr( array_init(|idx| { if idx == 0 { @@ -120,7 +125,7 @@ impl ExecutionGadget for SignextendGadget { ) } }), - cb.power_of_randomness(), + &powers_of_randomness, ); // Pop the byte index and the value from the stack, push the result on diff --git a/zkevm-circuits/src/evm_circuit/execution/sload.rs b/zkevm-circuits/src/evm_circuit/execution/sload.rs index d332875873..b6cdb5d98f 100644 --- a/zkevm-circuits/src/evm_circuit/execution/sload.rs +++ b/zkevm-circuits/src/evm_circuit/execution/sload.rs @@ -7,14 +7,14 @@ use crate::{ constraint_builder::{ ConstraintBuilder, ReversionInfo, StepStateTransition, Transition::Delta, }, - select, CachedRegion, Cell, Word, + select, CachedRegion, Cell, CellType, }, witness::{Block, Call, ExecStep, Transaction}, }, table::CallContextFieldTag, util::Expr, }; -use eth_types::{evm_types::GasCost, Field, ToLittleEndian, ToScalar}; +use eth_types::{evm_types::GasCost, Field, ToScalar}; use halo2_proofs::{ circuit::Value, plonk::{Error, Expression}, @@ -26,9 +26,9 @@ pub(crate) struct SloadGadget { tx_id: Cell, reversion_info: ReversionInfo, callee_address: Cell, - key: Cell, - value: Cell, - committed_value: Cell, + phase2_key: Cell, + phase2_value: Cell, + phase2_committed_value: Cell, is_warm: Cell, } @@ -44,27 +44,27 @@ impl ExecutionGadget for SloadGadget { let mut reversion_info = cb.reversion_info_read(None); let callee_address = cb.call_context(None, CallContextFieldTag::CalleeAddress); - let key = cb.query_cell(); + let phase2_key = cb.query_cell_with_type(CellType::StoragePhase2); // Pop the key from the stack - cb.stack_pop(key.expr()); + cb.stack_pop(phase2_key.expr()); - let value = cb.query_cell(); - let committed_value = cb.query_cell(); + let phase2_value = cb.query_cell_with_type(CellType::StoragePhase2); + let phase2_committed_value = cb.query_cell_with_type(CellType::StoragePhase2); cb.account_storage_read( callee_address.expr(), - key.expr(), - value.expr(), + phase2_key.expr(), + phase2_value.expr(), tx_id.expr(), - committed_value.expr(), + phase2_committed_value.expr(), ); - cb.stack_push(value.expr()); + cb.stack_push(phase2_value.expr()); let is_warm = cb.query_bool(); cb.account_storage_access_list_write( tx_id.expr(), callee_address.expr(), - key.expr(), + phase2_key.expr(), true.expr(), is_warm.expr(), Some(&mut reversion_info), @@ -85,9 +85,9 @@ impl ExecutionGadget for SloadGadget { tx_id, reversion_info, callee_address, - key, - value, - committed_value, + phase2_key, + phase2_value, + phase2_committed_value, is_warm, } } @@ -123,32 +123,14 @@ impl ExecutionGadget for SloadGadget { let [key, value] = [step.rw_indices[4], step.rw_indices[6]].map(|idx| block.rws[idx].stack_value()); - self.key.assign( - region, - offset, - Value::known(Word::random_linear_combine( - key.to_le_bytes(), - block.randomness, - )), - )?; - self.value.assign( - region, - offset, - Value::known(Word::random_linear_combine( - value.to_le_bytes(), - block.randomness, - )), - )?; + self.phase2_key + .assign(region, offset, region.word_rlc(key))?; + self.phase2_value + .assign(region, offset, region.word_rlc(value))?; let (_, committed_value) = block.rws[step.rw_indices[5]].aux_pair(); - self.committed_value.assign( - region, - offset, - Value::known(Word::random_linear_combine( - committed_value.to_le_bytes(), - block.randomness, - )), - )?; + self.phase2_committed_value + .assign(region, offset, region.word_rlc(committed_value))?; let (_, is_warm) = block.rws[step.rw_indices[7]].tx_access_list_value_pair(); self.is_warm diff --git a/zkevm-circuits/src/evm_circuit/execution/sstore.rs b/zkevm-circuits/src/evm_circuit/execution/sstore.rs index b2319e9c59..ef5889439a 100644 --- a/zkevm-circuits/src/evm_circuit/execution/sstore.rs +++ b/zkevm-circuits/src/evm_circuit/execution/sstore.rs @@ -8,7 +8,7 @@ use crate::{ ConstraintBuilder, ReversionInfo, StepStateTransition, Transition::Delta, }, math_gadget::{IsEqualGadget, IsZeroGadget}, - not, select, CachedRegion, Cell, Word, + not, select, CachedRegion, Cell, CellType, }, witness::{Block, Call, ExecStep, Transaction}, }, @@ -16,7 +16,7 @@ use crate::{ util::Expr, }; -use eth_types::{evm_types::GasCost, Field, ToLittleEndian, ToScalar}; +use eth_types::{evm_types::GasCost, Field, ToScalar}; use halo2_proofs::{ circuit::Value, plonk::{Error, Expression}, @@ -29,10 +29,10 @@ pub(crate) struct SstoreGadget { is_static: Cell, reversion_info: ReversionInfo, callee_address: Cell, - key: Cell, - value: Cell, - value_prev: Cell, - original_value: Cell, + phase2_key: Cell, + phase2_value: Cell, + phase2_value_prev: Cell, + phase2_original_value: Cell, is_warm: Cell, tx_refund_prev: Cell, gas_cost: SstoreGasGadget, @@ -56,23 +56,23 @@ impl ExecutionGadget for SstoreGadget { let mut reversion_info = cb.reversion_info_read(None); let callee_address = cb.call_context(None, CallContextFieldTag::CalleeAddress); - let key = cb.query_cell(); + let phase2_key = cb.query_cell_with_type(CellType::StoragePhase2); // Pop the key from the stack - cb.stack_pop(key.expr()); + cb.stack_pop(phase2_key.expr()); - let value = cb.query_cell(); + let phase2_value = cb.query_cell_with_type(CellType::StoragePhase2); // Pop the value from the stack - cb.stack_pop(value.expr()); + cb.stack_pop(phase2_value.expr()); - let value_prev = cb.query_cell(); - let original_value = cb.query_cell(); + let phase2_value_prev = cb.query_cell_with_type(CellType::StoragePhase2); + let phase2_original_value = cb.query_cell_with_type(CellType::StoragePhase2); cb.account_storage_write( callee_address.expr(), - key.expr(), - value.expr(), - value_prev.expr(), + phase2_key.expr(), + phase2_value.expr(), + phase2_value_prev.expr(), tx_id.expr(), - original_value.expr(), + phase2_original_value.expr(), Some(&mut reversion_info), ); @@ -80,7 +80,7 @@ impl ExecutionGadget for SstoreGadget { cb.account_storage_access_list_write( tx_id.expr(), callee_address.expr(), - key.expr(), + phase2_key.expr(), true.expr(), is_warm.expr(), Some(&mut reversion_info), @@ -88,9 +88,9 @@ impl ExecutionGadget for SstoreGadget { let gas_cost = SstoreGasGadget::construct( cb, - value.clone(), - value_prev.clone(), - original_value.clone(), + phase2_value.clone(), + phase2_value_prev.clone(), + phase2_original_value.clone(), is_warm.clone(), ); @@ -98,9 +98,9 @@ impl ExecutionGadget for SstoreGadget { let tx_refund = SstoreTxRefundGadget::construct( cb, tx_refund_prev.clone(), - value.clone(), - value_prev.clone(), - original_value.clone(), + phase2_value.clone(), + phase2_value_prev.clone(), + phase2_original_value.clone(), ); cb.tx_refund_write( tx_id.expr(), @@ -125,10 +125,10 @@ impl ExecutionGadget for SstoreGadget { is_static, reversion_info, callee_address, - key, - value, - value_prev, - original_value, + phase2_key, + phase2_value, + phase2_value_prev, + phase2_original_value, is_warm, tx_refund_prev, gas_cost, @@ -169,40 +169,16 @@ impl ExecutionGadget for SstoreGadget { let [key, value] = [step.rw_indices[5], step.rw_indices[6]].map(|idx| block.rws[idx].stack_value()); - self.key.assign( - region, - offset, - Value::known(Word::random_linear_combine( - key.to_le_bytes(), - block.randomness, - )), - )?; - self.value.assign( - region, - offset, - Value::known(Word::random_linear_combine( - value.to_le_bytes(), - block.randomness, - )), - )?; + self.phase2_key + .assign(region, offset, region.word_rlc(key))?; + self.phase2_value + .assign(region, offset, region.word_rlc(value))?; let (_, value_prev, _, original_value) = block.rws[step.rw_indices[7]].storage_value_aux(); - self.value_prev.assign( - region, - offset, - Value::known(Word::random_linear_combine( - value_prev.to_le_bytes(), - block.randomness, - )), - )?; - self.original_value.assign( - region, - offset, - Value::known(Word::random_linear_combine( - original_value.to_le_bytes(), - block.randomness, - )), - )?; + self.phase2_value_prev + .assign(region, offset, region.word_rlc(value_prev))?; + self.phase2_original_value + .assign(region, offset, region.word_rlc(original_value))?; let (_, is_warm) = block.rws[step.rw_indices[8]].tx_access_list_value_pair(); self.is_warm @@ -220,7 +196,6 @@ impl ExecutionGadget for SstoreGadget { value_prev, original_value, is_warm, - block.randomness, )?; self.tx_refund.assign( @@ -231,7 +206,6 @@ impl ExecutionGadget for SstoreGadget { value, value_prev, original_value, - block.randomness, )?; Ok(()) } @@ -307,48 +281,28 @@ impl SstoreGasGadget { value_prev: eth_types::Word, original_value: eth_types::Word, is_warm: bool, - randomness: F, ) -> Result<(), Error> { - self.value.assign( - region, - offset, - Value::known(Word::random_linear_combine(value.to_le_bytes(), randomness)), - )?; - self.value_prev.assign( - region, - offset, - Value::known(Word::random_linear_combine( - value_prev.to_le_bytes(), - randomness, - )), - )?; - self.original_value.assign( - region, - offset, - Value::known(Word::random_linear_combine( - original_value.to_le_bytes(), - randomness, - )), - )?; + self.value.assign(region, offset, region.word_rlc(value))?; + self.value_prev + .assign(region, offset, region.word_rlc(value_prev))?; + self.original_value + .assign(region, offset, region.word_rlc(original_value))?; self.is_warm .assign(region, offset, Value::known(F::from(is_warm as u64)))?; - self.value_eq_prev.assign( + self.value_eq_prev.assign_value( region, offset, - Word::random_linear_combine(value.to_le_bytes(), randomness), - Word::random_linear_combine(value_prev.to_le_bytes(), randomness), + region.word_rlc(value), + region.word_rlc(value_prev), )?; - self.original_eq_prev.assign( + self.original_eq_prev.assign_value( region, offset, - Word::random_linear_combine(original_value.to_le_bytes(), randomness), - Word::random_linear_combine(value_prev.to_le_bytes(), randomness), - )?; - self.original_is_zero.assign( - region, - offset, - Word::random_linear_combine(original_value.to_le_bytes(), randomness), + region.word_rlc(original_value), + region.word_rlc(value_prev), )?; + self.original_is_zero + .assign_value(region, offset, region.word_rlc(original_value))?; debug_assert_eq!( calc_expected_gas_cost(value, value_prev, original_value, is_warm), gas_cost @@ -452,63 +406,40 @@ impl SstoreTxRefundGadget { value: eth_types::Word, value_prev: eth_types::Word, original_value: eth_types::Word, - randomness: F, ) -> Result<(), Error> { self.tx_refund_old .assign(region, offset, Value::known(F::from(tx_refund_old)))?; - self.value.assign( - region, - offset, - Value::known(Word::random_linear_combine(value.to_le_bytes(), randomness)), - )?; - self.value_prev.assign( - region, - offset, - Value::known(Word::random_linear_combine( - value_prev.to_le_bytes(), - randomness, - )), - )?; - self.original_value.assign( - region, - offset, - Value::known(Word::random_linear_combine( - original_value.to_le_bytes(), - randomness, - )), - )?; - self.value_prev_is_zero_gadget.assign( - region, - offset, - Word::random_linear_combine(value_prev.to_le_bytes(), randomness), - )?; - self.value_is_zero_gadget.assign( - region, - offset, - Word::random_linear_combine(value.to_le_bytes(), randomness), - )?; - self.original_is_zero_gadget.assign( + self.value.assign(region, offset, region.word_rlc(value))?; + self.value_prev + .assign(region, offset, region.word_rlc(value_prev))?; + self.original_value + .assign(region, offset, region.word_rlc(original_value))?; + self.value_prev_is_zero_gadget + .assign_value(region, offset, region.word_rlc(value_prev))?; + self.value_is_zero_gadget + .assign_value(region, offset, region.word_rlc(value))?; + self.original_is_zero_gadget.assign_value( region, offset, - Word::random_linear_combine(original_value.to_le_bytes(), randomness), + region.word_rlc(original_value), )?; - self.original_eq_value_gadget.assign( + self.original_eq_value_gadget.assign_value( region, offset, - Word::random_linear_combine(original_value.to_le_bytes(), randomness), - Word::random_linear_combine(value.to_le_bytes(), randomness), + region.word_rlc(original_value), + region.word_rlc(value), )?; - self.prev_eq_value_gadget.assign( + self.prev_eq_value_gadget.assign_value( region, offset, - Word::random_linear_combine(value_prev.to_le_bytes(), randomness), - Word::random_linear_combine(value.to_le_bytes(), randomness), + region.word_rlc(value_prev), + region.word_rlc(value), )?; - self.original_eq_prev_gadget.assign( + self.original_eq_prev_gadget.assign_value( region, offset, - Word::random_linear_combine(original_value.to_le_bytes(), randomness), - Word::random_linear_combine(value_prev.to_le_bytes(), randomness), + region.word_rlc(original_value), + region.word_rlc(value_prev), )?; debug_assert_eq!( calc_expected_tx_refund(tx_refund_old, value, value_prev, original_value), diff --git a/zkevm-circuits/src/evm_circuit/execution/swap.rs b/zkevm-circuits/src/evm_circuit/execution/swap.rs index d9b7125db1..0808574def 100644 --- a/zkevm-circuits/src/evm_circuit/execution/swap.rs +++ b/zkevm-circuits/src/evm_circuit/execution/swap.rs @@ -5,19 +5,19 @@ use crate::{ util::{ common_gadget::SameContextGadget, constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, - CachedRegion, Cell, Word, + CachedRegion, Cell, CellType, }, witness::{Block, Call, ExecStep, Transaction}, }, util::Expr, }; -use eth_types::{evm_types::OpcodeId, Field, ToLittleEndian}; -use halo2_proofs::{circuit::Value, plonk::Error}; +use eth_types::{evm_types::OpcodeId, Field}; +use halo2_proofs::plonk::Error; #[derive(Clone, Debug)] pub(crate) struct SwapGadget { same_context: SameContextGadget, - values: [Cell; 2], + phase2_values: [Cell; 2], } impl ExecutionGadget for SwapGadget { @@ -28,20 +28,23 @@ impl ExecutionGadget for SwapGadget { fn configure(cb: &mut ConstraintBuilder) -> Self { let opcode = cb.query_cell(); - let values = [cb.query_cell(), cb.query_cell()]; + let phase2_values = [ + cb.query_cell_with_type(CellType::StoragePhase2), + cb.query_cell_with_type(CellType::StoragePhase2), + ]; // The stack index we have to peek, deduced from the 'x' value of // 'swapx' The offset starts at 1 for SWAP1 let swap_offset = opcode.expr() - (OpcodeId::SWAP1.as_u64() - 1).expr(); // Peek the value at `swap_offset` - cb.stack_lookup(false.expr(), swap_offset.clone(), values[0].expr()); + cb.stack_lookup(false.expr(), swap_offset.clone(), phase2_values[0].expr()); // Peek the value at the top of the stack - cb.stack_lookup(false.expr(), 0.expr(), values[1].expr()); + cb.stack_lookup(false.expr(), 0.expr(), phase2_values[1].expr()); // Write the value previously at the top of the stack to `swap_offset` - cb.stack_lookup(true.expr(), swap_offset, values[1].expr()); + cb.stack_lookup(true.expr(), swap_offset, phase2_values[1].expr()); // Write the value previously at `swap_offset` to the top of the stack - cb.stack_lookup(true.expr(), 0.expr(), values[0].expr()); + cb.stack_lookup(true.expr(), 0.expr(), phase2_values[0].expr()); // State transition let step_state_transition = StepStateTransition { @@ -54,7 +57,7 @@ impl ExecutionGadget for SwapGadget { Self { same_context, - values, + phase2_values, } } @@ -69,19 +72,12 @@ impl ExecutionGadget for SwapGadget { ) -> Result<(), Error> { self.same_context.assign_exec_step(region, offset, step)?; - for (cell, value) in self.values.iter().zip( + for (cell, value) in self.phase2_values.iter().zip( [step.rw_indices[0], step.rw_indices[1]] .map(|idx| block.rws[idx].stack_value()) .iter(), ) { - cell.assign( - region, - offset, - Value::known(Word::random_linear_combine( - value.to_le_bytes(), - block.randomness, - )), - )?; + cell.assign(region, offset, region.word_rlc(*value))?; } Ok(()) diff --git a/zkevm-circuits/src/evm_circuit/param.rs b/zkevm-circuits/src/evm_circuit/param.rs index b392318735..cf12b26b1f 100644 --- a/zkevm-circuits/src/evm_circuit/param.rs +++ b/zkevm-circuits/src/evm_circuit/param.rs @@ -10,6 +10,12 @@ pub const MAX_STEP_HEIGHT: usize = 21; pub(crate) const STEP_STATE_HEIGHT: usize = 1; pub(crate) const N_CELLS_STEP_STATE: usize = 11; +// Number of phase2 columns +pub(crate) const N_PHASE2_COLUMNS: usize = 2; + +// Number of phase3 columns +pub(crate) const N_PHASE3_COLUMNS: usize = 1; + // Number of copy columns pub(crate) const N_COPY_COLUMNS: usize = 2; diff --git a/zkevm-circuits/src/evm_circuit/step.rs b/zkevm-circuits/src/evm_circuit/step.rs index e83cd007d9..e6ca7baba9 100644 --- a/zkevm-circuits/src/evm_circuit/step.rs +++ b/zkevm-circuits/src/evm_circuit/step.rs @@ -2,13 +2,12 @@ use super::util::{CachedRegion, CellManager, CellType}; use crate::{ evm_circuit::{ param::{MAX_STEP_HEIGHT, STEP_STATE_HEIGHT, STEP_WIDTH}, - util::{Cell, RandomLinearCombination}, + util::Cell, witness::{Block, Call, ExecStep}, }, util::Expr, }; use bus_mapping::evm::OpcodeId; -use eth_types::ToLittleEndian; use halo2_proofs::{ arithmetic::FieldExt, circuit::Value, @@ -329,8 +328,8 @@ pub(crate) struct DynamicSelectorHalf { impl DynamicSelectorHalf { pub(crate) fn new(cell_manager: &mut CellManager, count: usize) -> Self { - let target_pairs = cell_manager.query_cells(CellType::Storage, (count + 1) / 2); - let target_odd = cell_manager.query_cell(CellType::Storage); + let target_pairs = cell_manager.query_cells(CellType::StoragePhase1, (count + 1) / 2); + let target_odd = cell_manager.query_cell(CellType::StoragePhase1); Self { count, target_pairs, @@ -472,17 +471,17 @@ impl Step { &mut cell_manager, 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_hash: 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), + rw_counter: cell_manager.query_cell(CellType::StoragePhase1), + call_id: cell_manager.query_cell(CellType::StoragePhase1), + is_root: cell_manager.query_cell(CellType::StoragePhase1), + is_create: cell_manager.query_cell(CellType::StoragePhase1), + code_hash: cell_manager.query_cell(CellType::StoragePhase2), + program_counter: cell_manager.query_cell(CellType::StoragePhase1), + stack_pointer: cell_manager.query_cell(CellType::StoragePhase1), + gas_left: cell_manager.query_cell(CellType::StoragePhase1), + memory_word_size: cell_manager.query_cell(CellType::StoragePhase1), + reversible_write_counter: cell_manager.query_cell(CellType::StoragePhase1), + log_id: cell_manager.query_cell(CellType::StoragePhase1), } }; Self { @@ -504,7 +503,7 @@ impl Step { &self, region: &mut CachedRegion<'_, '_, F>, offset: usize, - block: &Block, + _block: &Block, call: &Call, step: &ExecStep, ) -> Result<(), Error> { @@ -527,14 +526,9 @@ impl Step { offset, Value::known(F::from(call.is_create as u64)), )?; - self.state.code_hash.assign( - region, - offset, - Value::known(RandomLinearCombination::random_linear_combine( - call.code_hash.to_le_bytes(), - block.randomness, - )), - )?; + self.state + .code_hash + .assign(region, offset, region.word_rlc(call.code_hash))?; self.state.program_counter.assign( region, offset, diff --git a/zkevm-circuits/src/evm_circuit/util.rs b/zkevm-circuits/src/evm_circuit/util.rs index a979cf3f4b..575f3f86b2 100644 --- a/zkevm-circuits/src/evm_circuit/util.rs +++ b/zkevm-circuits/src/evm_circuit/util.rs @@ -1,10 +1,14 @@ use crate::{ evm_circuit::{ - param::{LOOKUP_CONFIG, N_BYTES_MEMORY_ADDRESS, N_COPY_COLUMNS}, + param::{ + LOOKUP_CONFIG, N_BYTES_MEMORY_ADDRESS, N_COPY_COLUMNS, N_PHASE2_COLUMNS, + N_PHASE3_COLUMNS, + }, table::Table, }, - util::{query_expression, Expr}, + util::{query_expression, Challenges, Expr}, }; +use eth_types::ToLittleEndian; use eth_types::U256; use halo2_proofs::{ arithmetic::FieldExt, @@ -13,7 +17,9 @@ use halo2_proofs::{ poly::Rotation, }; use itertools::Itertools; +use keccak256::EMPTY_HASH_LE; use std::collections::BTreeMap; +use std::hash::{Hash, Hasher}; pub(crate) mod common_gadget; pub(crate) mod constraint_builder; @@ -71,12 +77,11 @@ impl Expr for &Cell { self.expression.clone() } } - pub struct CachedRegion<'r, 'b, F: FieldExt> { region: &'r mut Region<'b, F>, advice: Vec>, + challenges: &'r Challenges>, advice_columns: Vec>, - power_of_randomness: [F; 31], width_start: usize, height_start: usize, } @@ -85,7 +90,7 @@ 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], + challenges: &'r Challenges>, advice_columns: Vec>, height: usize, height_start: usize, @@ -93,7 +98,7 @@ impl<'r, 'b, F: FieldExt> CachedRegion<'r, 'b, F> { Self { region, advice: vec![vec![F::zero(); height]; advice_columns.len()], - power_of_randomness, + challenges, width_start: advice_columns[0].index(), height_start, advice_columns, @@ -168,8 +173,17 @@ impl<'r, 'b, F: FieldExt> CachedRegion<'r, 'b, F> { [(((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] + pub fn challenges(&self) -> &Challenges> { + self.challenges + } + + pub fn word_rlc(&self, n: U256) -> Value { + self.challenges + .evm_word() + .map(|r| Word::random_linear_combine(n.to_le_bytes(), r)) + } + pub fn empty_hash_rlc(&self) -> Value { + self.word_rlc(U256::from_little_endian(&*EMPTY_HASH_LE)) } /// Constrains a cell to have a constant value. @@ -197,6 +211,13 @@ pub struct StoredExpression { expr_id: String, } +impl Hash for StoredExpression { + fn hash(&self, state: &mut H) { + self.expr_id.hash(state); + self.cell_type.hash(state); + } +} + impl StoredExpression { pub fn assign( &self, @@ -204,38 +225,70 @@ impl StoredExpression { offset: usize, ) -> Result, Error> { let value = self.expr.evaluate( - &|scalar| scalar, + &|scalar| Value::known(scalar), &|_| unimplemented!("selector column"), &|fixed_query| { - region.get_fixed(offset, fixed_query.column_index(), fixed_query.rotation()) + Value::known(region.get_fixed( + offset, + fixed_query.column_index(), + fixed_query.rotation(), + )) }, &|advide_query| { - region.get_advice(offset, advide_query.column_index(), advide_query.rotation()) - }, - &|instance_query| { - region.get_instance( + Value::known(region.get_advice( offset, - instance_query.column_index(), - instance_query.rotation(), - ) + advide_query.column_index(), + advide_query.rotation(), + )) }, - &|_| unimplemented!(), + &|_| unimplemented!("instance column"), + &|challenge| *region.challenges().indexed()[challenge.index()], &|a| -a, &|a, b| a + b, &|a, b| a * b, - &|a, scalar| a * scalar, + &|a, scalar| a * Value::known(scalar), ); - self.cell.assign(region, offset, Value::known(value)) + self.cell.assign(region, offset, value) } } -#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub(crate) enum CellType { - Storage, + StoragePhase1, + StoragePhase2, + StoragePhase3, StoragePermutation, Lookup(Table), } +impl CellType { + // The phase that given `Expression` becomes evaluateable. + fn expr_phase(expr: &Expression) -> u8 { + use Expression::*; + match expr { + Challenge(challenge) => challenge.phase() + 1, + Constant(_) | Selector(_) | Fixed(_) | Advice(_) | Instance(_) => 0, + Negated(a) | Expression::Scaled(a, _) => Self::expr_phase(a), + Sum(a, b) | Product(a, b) => std::cmp::max(Self::expr_phase(a), Self::expr_phase(b)), + } + } + + /// Return the storage phase of phase + pub(crate) fn storage_for_phase(phase: u8) -> CellType { + match phase { + 0 => CellType::StoragePhase1, + 1 => CellType::StoragePhase2, + 2 => CellType::StoragePhase3, + _ => unreachable!(), + } + } + + /// Return the storage cell of the expression + pub(crate) fn storage_for_expr(expr: &Expression) -> CellType { + Self::storage_for_phase::(Self::expr_phase::(expr)) + } +} + #[derive(Clone, Debug)] pub(crate) struct CellColumn { pub(crate) index: usize, @@ -276,21 +329,34 @@ impl CellManager { } columns.push(CellColumn { index: c, - cell_type: CellType::Storage, + cell_type: CellType::StoragePhase1, height: 0, expr: cells[c * height].expr(), }); } }); - // Mark columns used for lookups + // Mark columns used for Phase3 constraints let mut column_idx = 0; + for _ in 0..N_PHASE3_COLUMNS { + columns[column_idx].cell_type = CellType::StoragePhase3; + column_idx += 1; + } + + // Mark columns used for lookups in Phase3 for &(table, count) in LOOKUP_CONFIG { for _ in 0usize..count { columns[column_idx].cell_type = CellType::Lookup(table); column_idx += 1; } } + + // Mark columns used for Phase2 constraints + for _ in 0..N_PHASE2_COLUMNS { + columns[column_idx].cell_type = CellType::StoragePhase2; + column_idx += 1; + } + // Mark columns used for copy constraints for _ in 0..N_COPY_COLUMNS { meta.enable_equality(advices[column_idx]); @@ -332,7 +398,7 @@ impl CellManager { } // Replace a CellType::Storage by CellType::StoragePermutation if the later has // better height - if cell_type == CellType::Storage { + if cell_type == CellType::StoragePhase1 { for column in self.columns.iter() { if column.cell_type == CellType::StoragePermutation && column.height < best_height { best_index = Some(column.index); @@ -523,3 +589,12 @@ pub(crate) fn split_u256_limb64(value: &U256) -> [U256; 4] { U256([value.0[3], 0, 0, 0]), ] } + +/// Transposes an `Value` of a [`Result`] into a [`Result`] of an `Value`. +pub(crate) fn transpose_val_ret(value: Value>) -> Result, E> { + let mut ret = Ok(Value::unknown()); + value.map(|value| { + ret = value.map(Value::known); + }); + ret +} diff --git a/zkevm-circuits/src/evm_circuit/util/common_gadget.rs b/zkevm-circuits/src/evm_circuit/util/common_gadget.rs index e1a3ab68c3..e0359b7d5a 100644 --- a/zkevm-circuits/src/evm_circuit/util/common_gadget.rs +++ b/zkevm-circuits/src/evm_circuit/util/common_gadget.rs @@ -16,7 +16,7 @@ use crate::{ util::Expr, witness::{Block, Call, ExecStep}, }; -use eth_types::{evm_types::GasCost, Field, ToLittleEndian, ToScalar, U256}; +use eth_types::{evm_types::GasCost, Field, ToScalar, U256}; use halo2_proofs::{ circuit::Value, plonk::{Error, Expression}, @@ -235,14 +235,8 @@ impl RestoreContextGadget { )?; } - self.caller_code_hash.assign( - region, - offset, - Value::known(Word::random_linear_combine( - caller_code_hash.to_le_bytes(), - block.randomness, - )), - )?; + self.caller_code_hash + .assign(region, offset, region.word_rlc(caller_code_hash))?; Ok(()) } @@ -264,8 +258,8 @@ impl ) -> Self { debug_assert!(updates.len() == N_ADDENDS - 1); - let balance_addend = cb.query_word(); - let balance_sum = cb.query_word(); + let balance_addend = cb.query_word_rlc(); + let balance_sum = cb.query_word_rlc(); let [value, value_prev] = if INCREASE { [balance_sum.expr(), balance_addend.expr()] diff --git a/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs b/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs index a6ea091cb5..c18d81f4e0 100644 --- a/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs +++ b/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs @@ -9,7 +9,7 @@ use crate::{ AccountFieldTag, BytecodeFieldTag, CallContextFieldTag, RwTableTag, TxContextFieldTag, TxLogFieldTag, TxReceiptFieldTag, }, - util::{build_tx_log_expression, Expr}, + util::{build_tx_log_expression, Challenges, Expr}, }; use eth_types::Field; use gadgets::util::{and, not}; @@ -20,6 +20,7 @@ use halo2_proofs::{ Expression::{self, Constant}, }, }; +use keccak256::EMPTY_HASH_LE; use super::{rlc, CachedRegion, CellType, StoredExpression}; @@ -264,7 +265,9 @@ pub(crate) struct ConstraintBuilder<'a, F> { pub max_degree: usize, pub(crate) curr: Step, pub(crate) next: Step, - power_of_randomness: &'a [Expression; 31], + challenges: &'a Challenges>, + word_powers_of_randomness: &'a [Expression; 31], + lookup_powers_of_randomness: &'a [Expression; 12], execution_state: ExecutionState, constraints: Constraints, rw_counter_offset: Expression, @@ -281,14 +284,16 @@ impl<'a, F: Field> ConstraintBuilder<'a, F> { pub(crate) fn new( curr: Step, next: Step, - power_of_randomness: &'a [Expression; 31], + challenges: &'a Challenges>, + word_powers_of_randomness: &'a [Expression; 31], + lookup_powers_of_randomness: &'a [Expression; 12], execution_state: ExecutionState, ) -> Self { Self { max_degree: MAX_DEGREE, curr, next, - power_of_randomness, + challenges, execution_state, constraints: Constraints { step: Vec::new(), @@ -304,6 +309,8 @@ impl<'a, F: Field> ConstraintBuilder<'a, F> { condition: None, constraints_location: ConstraintLocation::Step, stored_expressions: Vec::new(), + word_powers_of_randomness, + lookup_powers_of_randomness, } } @@ -329,8 +336,8 @@ impl<'a, F: Field> ConstraintBuilder<'a, F> { ) } - pub(crate) fn power_of_randomness(&self) -> &[Expression] { - self.power_of_randomness + pub(crate) fn challenges(&self) -> &Challenges> { + self.challenges } pub(crate) fn execution_state(&self) -> ExecutionState { @@ -371,12 +378,8 @@ impl<'a, F: Field> ConstraintBuilder<'a, F> { self.query_cell_with_type(CellType::Lookup(Table::Byte)) } - pub(crate) fn query_word(&mut self) -> Word { - self.query_rlc() - } - - pub(crate) fn query_rlc(&mut self) -> RandomLinearCombination { - RandomLinearCombination::::new(self.query_bytes(), self.power_of_randomness) + pub(crate) fn query_word_rlc(&mut self) -> RandomLinearCombination { + RandomLinearCombination::::new(self.query_bytes(), self.word_powers_of_randomness) } pub(crate) fn query_bytes(&mut self) -> [Cell; N] { @@ -388,7 +391,7 @@ impl<'a, F: Field> ConstraintBuilder<'a, F> { } pub(crate) fn query_cell(&mut self) -> Cell { - self.query_cell_with_type(CellType::Storage) + self.query_cell_with_type(CellType::StoragePhase1) } pub(crate) fn query_copy_cell(&mut self) -> Cell { @@ -399,6 +402,12 @@ impl<'a, F: Field> ConstraintBuilder<'a, F> { self.query_cells(cell_type, 1).first().unwrap().clone() } + pub(crate) fn query_bool_with_type(&mut self, cell_type: CellType) -> Cell { + let cell = self.query_cell_with_type(cell_type); + self.require_boolean("Constrain cell to be a bool", cell.expr()); + cell + } + fn query_cells(&mut self, cell_type: CellType, count: usize) -> Vec> { if self.in_next_step { &mut self.next @@ -409,6 +418,14 @@ impl<'a, F: Field> ConstraintBuilder<'a, F> { .query_cells(cell_type, count) } + pub(crate) fn word_rlc(&self, bytes: [Expression; N]) -> Expression { + RandomLinearCombination::random_linear_combine_expr(bytes, self.word_powers_of_randomness) + } + + pub(crate) fn empty_hash_rlc(&self) -> Expression { + self.word_rlc((*EMPTY_HASH_LE).map(|byte| byte.expr())) + } + // Common pub(crate) fn require_zero(&mut self, name: &'static str, constraint: Expression) { @@ -629,7 +646,7 @@ impl<'a, F: Field> ConstraintBuilder<'a, F> { field_tag: TxContextFieldTag, index: Option>, ) -> Word { - let word = self.query_word(); + let word = self.query_word_rlc(); self.tx_context_lookup(id, field_tag, index, word.expr()); word } @@ -1000,7 +1017,11 @@ impl<'a, F: Field> ConstraintBuilder<'a, F> { call_id: Option>, field_tag: CallContextFieldTag, ) -> Cell { - let cell = self.query_cell(); + let phase = match field_tag { + CallContextFieldTag::CodeHash => CellType::StoragePhase2, + _ => CellType::StoragePhase1, + }; + let cell = self.query_cell_with_type(phase); self.call_context_lookup(false.expr(), call_id, field_tag, cell.expr()); cell } @@ -1010,7 +1031,7 @@ impl<'a, F: Field> ConstraintBuilder<'a, F> { call_id: Option>, field_tag: CallContextFieldTag, ) -> Word { - let word = self.query_word(); + let word = self.query_word_rlc(); self.call_context_lookup(false.expr(), call_id, field_tag, word.expr()); word } @@ -1410,10 +1431,9 @@ impl<'a, F: Field> ConstraintBuilder<'a, F> { Some(condition) => lookup.conditional(condition.clone()), None => lookup, }; - let compressed_expr = self.split_expression( "Lookup compression", - rlc::expr(&lookup.input_exprs(), self.power_of_randomness), + rlc::expr(&lookup.input_exprs(), self.lookup_powers_of_randomness), MAX_DEGREE - IMPLICIT_DEGREE, ); self.store_expression(name, compressed_expr, CellType::Lookup(lookup.table())); @@ -1426,7 +1446,8 @@ impl<'a, F: Field> ConstraintBuilder<'a, F> { cell_type: CellType, ) -> Expression { // Check if we already stored the expression somewhere - let stored_expression = self.find_stored_expression(expr.clone(), cell_type); + let stored_expression = self.find_stored_expression(&expr, cell_type); + match stored_expression { Some(stored_expression) => { debug_assert!( @@ -1464,7 +1485,7 @@ impl<'a, F: Field> ConstraintBuilder<'a, F> { pub(crate) fn find_stored_expression( &self, - expr: Expression, + expr: &Expression, cell_type: CellType, ) -> Option<&StoredExpression> { let expr_id = expr.identifier(); @@ -1499,7 +1520,8 @@ impl<'a, F: Field> ConstraintBuilder<'a, F> { if expr.degree() > max_degree { self.split_expression(name, expr, max_degree) } else { - self.store_expression(name, expr, CellType::Storage) + let cell_type = CellType::storage_for_expr(&expr); + self.store_expression(name, expr, cell_type) } }; if a.degree() >= b.degree() { diff --git a/zkevm-circuits/src/evm_circuit/util/math_gadget/abs_word.rs b/zkevm-circuits/src/evm_circuit/util/math_gadget/abs_word.rs index 1c6c36cd70..c668798775 100644 --- a/zkevm-circuits/src/evm_circuit/util/math_gadget/abs_word.rs +++ b/zkevm-circuits/src/evm_circuit/util/math_gadget/abs_word.rs @@ -24,9 +24,9 @@ pub(crate) struct AbsWordGadget { impl AbsWordGadget { pub(crate) fn construct(cb: &mut ConstraintBuilder) -> Self { - let x = cb.query_word(); - let x_abs = cb.query_word(); - let sum = cb.query_word(); + let x = cb.query_word_rlc(); + let x_abs = cb.query_word_rlc(); + let sum = cb.query_word_rlc(); let x_lo = from_bytes::expr(&x.cells[0..16]); let x_hi = from_bytes::expr(&x.cells[16..32]); let x_abs_lo = from_bytes::expr(&x_abs.cells[0..16]); diff --git a/zkevm-circuits/src/evm_circuit/util/math_gadget/add_words.rs b/zkevm-circuits/src/evm_circuit/util/math_gadget/add_words.rs index 397643d7f5..204e857ea3 100644 --- a/zkevm-circuits/src/evm_circuit/util/math_gadget/add_words.rs +++ b/zkevm-circuits/src/evm_circuit/util/math_gadget/add_words.rs @@ -170,8 +170,8 @@ mod tests { MathGadgetContainer for AddWordsTestContainer { fn configure_gadget_container(cb: &mut ConstraintBuilder) -> Self { - let addends = [(); N_ADDENDS].map(|_| cb.query_word()); - let sum = cb.query_word(); + let addends = [(); N_ADDENDS].map(|_| cb.query_word_rlc()); + let sum = cb.query_word_rlc(); let addwords_gadget = AddWordsGadget::::construct( cb, addends.clone(), diff --git a/zkevm-circuits/src/evm_circuit/util/math_gadget/batched_is_zero.rs b/zkevm-circuits/src/evm_circuit/util/math_gadget/batched_is_zero.rs index 4edbe4a910..a23af6c2e4 100644 --- a/zkevm-circuits/src/evm_circuit/util/math_gadget/batched_is_zero.rs +++ b/zkevm-circuits/src/evm_circuit/util/math_gadget/batched_is_zero.rs @@ -1,5 +1,7 @@ use crate::{ - evm_circuit::util::{constraint_builder::ConstraintBuilder, CachedRegion, Cell}, + evm_circuit::util::{ + constraint_builder::ConstraintBuilder, transpose_val_ret, CachedRegion, Cell, CellType, + }, util::Expr, }; use eth_types::Field; @@ -16,8 +18,15 @@ pub struct BatchedIsZeroGadget { impl BatchedIsZeroGadget { pub(crate) fn construct(cb: &mut ConstraintBuilder, values: [Expression; N]) -> Self { - let is_zero = cb.query_bool(); - let nonempty_witness = cb.query_cell(); + let max_values_phase = values + .iter() + .map(CellType::expr_phase) + .max() + .expect("BatchedIsZeroGadget needs at least one expression"); + + let cell_type = CellType::storage_for_phase::(max_values_phase); + let is_zero = cb.query_bool_with_type(cell_type); + let nonempty_witness = cb.query_cell_with_type(cell_type); for value in values.iter() { cb.require_zero( @@ -61,6 +70,17 @@ impl BatchedIsZeroGadget { Ok(is_zero) } + + pub(crate) fn assign_value( + &self, + region: &mut CachedRegion<'_, '_, F>, + offset: usize, + values: [Value; N], + ) -> Result, Error> { + let values: Value<[F; N]> = + Value::>::from_iter(values).map(|vv| vv.try_into().unwrap()); + transpose_val_ret(values.map(|values| self.assign(region, offset, values))) + } } #[cfg(test)] diff --git a/zkevm-circuits/src/evm_circuit/util/math_gadget/byte_size.rs b/zkevm-circuits/src/evm_circuit/util/math_gadget/byte_size.rs index e5e865b85c..8c1a4b5145 100644 --- a/zkevm-circuits/src/evm_circuit/util/math_gadget/byte_size.rs +++ b/zkevm-circuits/src/evm_circuit/util/math_gadget/byte_size.rs @@ -123,7 +123,7 @@ mod tests { impl MathGadgetContainer for ByteSizeGadgetContainer { fn configure_gadget_container(cb: &mut ConstraintBuilder) -> Self { - let value_rlc = cb.query_word(); + let value_rlc = cb.query_word_rlc(); let bytesize_gadget = ByteSizeGadget::::construct(cb, &value_rlc); cb.require_equal( "byte size gadget must equal N", diff --git a/zkevm-circuits/src/evm_circuit/util/math_gadget/cmp_words.rs b/zkevm-circuits/src/evm_circuit/util/math_gadget/cmp_words.rs index 2f3e9c3c9e..9fd044cc70 100644 --- a/zkevm-circuits/src/evm_circuit/util/math_gadget/cmp_words.rs +++ b/zkevm-circuits/src/evm_circuit/util/math_gadget/cmp_words.rs @@ -103,8 +103,8 @@ mod tests { for CmpWordGadgetTestContainer { fn configure_gadget_container(cb: &mut ConstraintBuilder) -> Self { - let a = cb.query_word(); - let b = cb.query_word(); + let a = cb.query_word_rlc(); + let b = cb.query_word_rlc(); let cmp_gadget = CmpWordsGadget::::construct(cb, &a, &b); cb.require_equal( "(a < b) * (a == b) == 0", diff --git a/zkevm-circuits/src/evm_circuit/util/math_gadget/constant_division.rs b/zkevm-circuits/src/evm_circuit/util/math_gadget/constant_division.rs index 6b8dea54ec..52589c68c0 100644 --- a/zkevm-circuits/src/evm_circuit/util/math_gadget/constant_division.rs +++ b/zkevm-circuits/src/evm_circuit/util/math_gadget/constant_division.rs @@ -1,6 +1,7 @@ use crate::{ evm_circuit::util::{ - constraint_builder::ConstraintBuilder, math_gadget::*, CachedRegion, Cell, + constraint_builder::ConstraintBuilder, math_gadget::*, transpose_val_ret, CachedRegion, + Cell, CellType, }, util::Expr, }; @@ -29,8 +30,8 @@ impl ConstantDivisionGadget { numerator: Expression, denominator: u64, ) -> Self { - let quotient = cb.query_cell(); - let remainder = cb.query_cell(); + let quotient = cb.query_cell_with_type(CellType::storage_for_expr(&numerator)); + let remainder = cb.query_cell_with_type(CellType::storage_for_expr(&numerator)); // Require that remainder < denominator cb.range_lookup(remainder.expr(), denominator); @@ -82,6 +83,17 @@ impl ConstantDivisionGadget { Ok((quotient, remainder)) } + + pub(crate) fn assign_value( + &self, + region: &mut CachedRegion<'_, '_, F>, + offset: usize, + numerator: Value, + ) -> Result, Error> { + transpose_val_ret( + numerator.map(|numerator| self.assign(region, offset, numerator.get_lower_128())), + ) + } } #[cfg(test)] diff --git a/zkevm-circuits/src/evm_circuit/util/math_gadget/is_equal.rs b/zkevm-circuits/src/evm_circuit/util/math_gadget/is_equal.rs index 13f46ba887..c731173790 100644 --- a/zkevm-circuits/src/evm_circuit/util/math_gadget/is_equal.rs +++ b/zkevm-circuits/src/evm_circuit/util/math_gadget/is_equal.rs @@ -1,9 +1,12 @@ use crate::evm_circuit::{ util::constraint_builder::ConstraintBuilder, - util::{math_gadget::*, CachedRegion}, + util::{math_gadget::*, transpose_val_ret, CachedRegion}, }; use eth_types::Field; -use halo2_proofs::plonk::{Error, Expression}; +use halo2_proofs::{ + circuit::Value, + plonk::{Error, Expression}, +}; /// Returns `1` when `lhs == rhs`, and returns `0` otherwise. #[derive(Clone, Debug)] @@ -35,6 +38,19 @@ impl IsEqualGadget { ) -> Result { self.is_zero.assign(region, offset, lhs - rhs) } + + pub(crate) fn assign_value( + &self, + region: &mut CachedRegion<'_, '_, F>, + offset: usize, + lhs: Value, + rhs: Value, + ) -> Result, Error> { + transpose_val_ret( + lhs.zip(rhs) + .map(|(lhs, rhs)| self.assign(region, offset, lhs, rhs)), + ) + } } #[cfg(test)] diff --git a/zkevm-circuits/src/evm_circuit/util/math_gadget/is_zero.rs b/zkevm-circuits/src/evm_circuit/util/math_gadget/is_zero.rs index 74ed36a683..b553c71365 100644 --- a/zkevm-circuits/src/evm_circuit/util/math_gadget/is_zero.rs +++ b/zkevm-circuits/src/evm_circuit/util/math_gadget/is_zero.rs @@ -1,5 +1,7 @@ use crate::{ - evm_circuit::util::{constraint_builder::ConstraintBuilder, CachedRegion, Cell}, + evm_circuit::util::{ + constraint_builder::ConstraintBuilder, transpose_val_ret, CachedRegion, Cell, CellType, + }, util::Expr, }; use eth_types::Field; @@ -17,7 +19,7 @@ pub struct IsZeroGadget { impl IsZeroGadget { pub(crate) fn construct(cb: &mut ConstraintBuilder, value: Expression) -> Self { - let inverse = cb.query_cell(); + let inverse = cb.query_cell_with_type(CellType::storage_for_expr(&value)); let is_zero = 1.expr() - (value.clone() * inverse.expr()); // when `value != 0` check `inverse = a.invert()`: value * (1 - value * @@ -51,6 +53,15 @@ impl IsZeroGadget { F::zero() }) } + + pub(crate) fn assign_value( + &self, + region: &mut CachedRegion<'_, '_, F>, + offset: usize, + value: Value, + ) -> Result, Error> { + transpose_val_ret(value.map(|value| self.assign(region, offset, value))) + } } #[cfg(test)] diff --git a/zkevm-circuits/src/evm_circuit/util/math_gadget/lt.rs b/zkevm-circuits/src/evm_circuit/util/math_gadget/lt.rs index 8ac418d126..ab7c7a8fc3 100644 --- a/zkevm-circuits/src/evm_circuit/util/math_gadget/lt.rs +++ b/zkevm-circuits/src/evm_circuit/util/math_gadget/lt.rs @@ -1,6 +1,7 @@ use crate::{ evm_circuit::util::{ - constraint_builder::ConstraintBuilder, from_bytes, pow_of_two, CachedRegion, Cell, + constraint_builder::ConstraintBuilder, from_bytes, pow_of_two, transpose_val_ret, + CachedRegion, Cell, }, util::Expr, }; @@ -83,6 +84,19 @@ impl LtGadget { pub(crate) fn diff_bytes(&self) -> Vec> { self.diff.to_vec() } + + pub(crate) fn assign_value( + &self, + region: &mut CachedRegion<'_, '_, F>, + offset: usize, + lhs: Value, + rhs: Value, + ) -> Result)>, Error> { + transpose_val_ret( + lhs.zip(rhs) + .map(|(lhs, rhs)| self.assign(region, offset, lhs, rhs)), + ) + } } #[cfg(test)] diff --git a/zkevm-circuits/src/evm_circuit/util/math_gadget/lt_word.rs b/zkevm-circuits/src/evm_circuit/util/math_gadget/lt_word.rs index ed82b9500b..ae1408a348 100644 --- a/zkevm-circuits/src/evm_circuit/util/math_gadget/lt_word.rs +++ b/zkevm-circuits/src/evm_circuit/util/math_gadget/lt_word.rs @@ -83,8 +83,8 @@ mod tests { impl MathGadgetContainer for LtWordTestContainer { fn configure_gadget_container(cb: &mut ConstraintBuilder) -> Self { - let a = cb.query_word(); - let b = cb.query_word(); + let a = cb.query_word_rlc(); + let b = cb.query_word_rlc(); let ltword_gadget = LtWordGadget::::construct(cb, &a, &b); cb.require_equal("a < b", ltword_gadget.expr(), 1.expr()); LtWordTestContainer { diff --git a/zkevm-circuits/src/evm_circuit/util/math_gadget/min_max.rs b/zkevm-circuits/src/evm_circuit/util/math_gadget/min_max.rs index 1857530262..3cf605be0e 100644 --- a/zkevm-circuits/src/evm_circuit/util/math_gadget/min_max.rs +++ b/zkevm-circuits/src/evm_circuit/util/math_gadget/min_max.rs @@ -1,8 +1,11 @@ use crate::evm_circuit::util::{ - constraint_builder::ConstraintBuilder, math_gadget::*, select, CachedRegion, + constraint_builder::ConstraintBuilder, math_gadget::*, select, transpose_val_ret, CachedRegion, }; use eth_types::Field; -use halo2_proofs::plonk::{Error, Expression}; +use halo2_proofs::{ + circuit::Value, + plonk::{Error, Expression}, +}; /// Returns `rhs` when `lhs < rhs`, and returns `lhs` otherwise. /// lhs and rhs `< 256**N_BYTES` /// `N_BYTES` is required to be `<= MAX_N_BYTES_INTEGER`. @@ -48,6 +51,19 @@ impl MinMaxGadget { (lhs, rhs) }) } + + pub(crate) fn assign_value( + &self, + region: &mut CachedRegion<'_, '_, F>, + offset: usize, + lhs: Value, + rhs: Value, + ) -> Result, Error> { + transpose_val_ret( + lhs.zip(rhs) + .map(|(lhs, rhs)| self.assign(region, offset, lhs, rhs)), + ) + } } #[cfg(test)] diff --git a/zkevm-circuits/src/evm_circuit/util/math_gadget/modulo.rs b/zkevm-circuits/src/evm_circuit/util/math_gadget/modulo.rs index 06e2c64a01..2f62f5d181 100644 --- a/zkevm-circuits/src/evm_circuit/util/math_gadget/modulo.rs +++ b/zkevm-circuits/src/evm_circuit/util/math_gadget/modulo.rs @@ -29,8 +29,8 @@ pub(crate) struct ModGadget { impl ModGadget { pub(crate) fn construct(cb: &mut ConstraintBuilder, words: [&util::Word; 3]) -> Self { let (a, n, r) = (words[0], words[1], words[2]); - let k = cb.query_word(); - let a_or_zero = cb.query_word(); + let k = cb.query_word_rlc(); + let a_or_zero = cb.query_word_rlc(); let n_is_zero = IsZeroGadget::construct(cb, sum::expr(&n.cells)); let a_or_is_zero = IsZeroGadget::construct(cb, sum::expr(&a_or_zero.cells)); let mul_add_words = MulAddWordsGadget::construct(cb, [&k, n, r, &a_or_zero]); @@ -72,7 +72,6 @@ impl ModGadget { n: Word, r: Word, k: Word, - randomness: F, ) -> Result<(), Error> { let a_or_zero = if n.is_zero() { Word::zero() } else { a }; @@ -87,11 +86,11 @@ impl ModGadget { self.mul_add_words .assign(region, offset, [k, n, r, a_or_zero])?; self.lt.assign(region, offset, r, n)?; - self.eq.assign( + self.eq.assign_value( region, offset, - util::Word::random_linear_combine(a.to_le_bytes(), randomness), - util::Word::random_linear_combine(a_or_zero.to_le_bytes(), randomness), + region.word_rlc(a), + region.word_rlc(a_or_zero), )?; Ok(()) @@ -117,9 +116,9 @@ mod tests { impl MathGadgetContainer for ModGadgetTestContainer { fn configure_gadget_container(cb: &mut ConstraintBuilder) -> Self { - let a = cb.query_word(); - let n = cb.query_word(); - let r = cb.query_word(); + let a = cb.query_word_rlc(); + let n = cb.query_word_rlc(); + let r = cb.query_word_rlc(); let mod_gadget = ModGadget::::construct(cb, [&a, &n, &r]); ModGadgetTestContainer { mod_gadget, @@ -149,7 +148,7 @@ mod tests { self.n.assign(region, offset, Some(n.to_le_bytes()))?; self.r.assign(region, offset, Some(r.to_le_bytes()))?; - self.mod_gadget.assign(region, 0, a, n, r, k, F::one()) + self.mod_gadget.assign(region, 0, a, n, r, k) } } diff --git a/zkevm-circuits/src/evm_circuit/util/math_gadget/mul_add_words.rs b/zkevm-circuits/src/evm_circuit/util/math_gadget/mul_add_words.rs index 6e2df1ccd5..eeecbe623b 100644 --- a/zkevm-circuits/src/evm_circuit/util/math_gadget/mul_add_words.rs +++ b/zkevm-circuits/src/evm_circuit/util/math_gadget/mul_add_words.rs @@ -168,10 +168,10 @@ mod tests { impl MathGadgetContainer for MulAddGadgetContainer { fn configure_gadget_container(cb: &mut ConstraintBuilder) -> Self { - let a = cb.query_word(); - let b = cb.query_word(); - let c = cb.query_word(); - let d = cb.query_word(); + let a = cb.query_word_rlc(); + let b = cb.query_word_rlc(); + let c = cb.query_word_rlc(); + let d = cb.query_word_rlc(); let carry = cb.query_cell(); let math_gadget = MulAddWordsGadget::::construct(cb, [&a, &b, &c, &d]); cb.require_equal("carry is correct", math_gadget.overflow(), carry.expr()); diff --git a/zkevm-circuits/src/evm_circuit/util/math_gadget/mul_add_words512.rs b/zkevm-circuits/src/evm_circuit/util/math_gadget/mul_add_words512.rs index eba3f5582e..0f47b14556 100644 --- a/zkevm-circuits/src/evm_circuit/util/math_gadget/mul_add_words512.rs +++ b/zkevm-circuits/src/evm_circuit/util/math_gadget/mul_add_words512.rs @@ -213,11 +213,11 @@ mod tests { impl MathGadgetContainer for MulAddWords512GadgetContainer { fn configure_gadget_container(cb: &mut ConstraintBuilder) -> Self { - let a = cb.query_word(); - let b = cb.query_word(); - let d = cb.query_word(); - let e = cb.query_word(); - let addend = cb.query_word(); + let a = cb.query_word_rlc(); + let b = cb.query_word_rlc(); + let d = cb.query_word_rlc(); + let e = cb.query_word_rlc(); + let addend = cb.query_word_rlc(); let math_gadget = MulAddWords512Gadget::::construct(cb, [&a, &b, &d, &e], Some(&addend)); MulAddWords512GadgetContainer { diff --git a/zkevm-circuits/src/evm_circuit/util/math_gadget/mul_word_u64.rs b/zkevm-circuits/src/evm_circuit/util/math_gadget/mul_word_u64.rs index 80392437fb..6556a934c7 100644 --- a/zkevm-circuits/src/evm_circuit/util/math_gadget/mul_word_u64.rs +++ b/zkevm-circuits/src/evm_circuit/util/math_gadget/mul_word_u64.rs @@ -28,7 +28,7 @@ impl MulWordByU64Gadget { ) -> Self { let gadget = Self { multiplicand, - product: cb.query_word(), + product: cb.query_word_rlc(), carry_lo: cb.query_bytes(), }; @@ -109,9 +109,9 @@ mod tests { impl MathGadgetContainer for MulWordByU64TestContainer { fn configure_gadget_container(cb: &mut ConstraintBuilder) -> Self { - let a = cb.query_word(); + let a = cb.query_word_rlc(); let b = cb.query_cell(); - let product = cb.query_word(); + let product = cb.query_word_rlc(); let mulwords_u64_gadget = MulWordByU64Gadget::::construct(cb, a.clone(), b.expr()); MulWordByU64TestContainer { mulwords_u64_gadget, diff --git a/zkevm-circuits/src/evm_circuit/util/math_gadget/test_util.rs b/zkevm-circuits/src/evm_circuit/util/math_gadget/test_util.rs index 1f35615b26..8a5c0cf2a6 100644 --- a/zkevm-circuits/src/evm_circuit/util/math_gadget/test_util.rs +++ b/zkevm-circuits/src/evm_circuit/util/math_gadget/test_util.rs @@ -2,17 +2,20 @@ use itertools::Itertools; use std::marker::PhantomData; use strum::IntoEnumIterator; -use crate::evm_circuit::{ - param::{MAX_STEP_HEIGHT, STEP_WIDTH}, - step::{ExecutionState, Step}, - table::{FixedTableTag, Table}, - util::{ - constraint_builder::ConstraintBuilder, rlc, CachedRegion, CellType, Expr, StoredExpression, +use crate::table::LookupTable; +use crate::{ + evm_circuit::{ + param::{MAX_STEP_HEIGHT, STEP_WIDTH}, + step::{ExecutionState, Step}, + table::{FixedTableTag, Table}, + util::{ + constraint_builder::ConstraintBuilder, rlc, CachedRegion, CellType, Expr, + StoredExpression, + }, + Advice, Column, Fixed, }, - Advice, Column, Fixed, + util::Challenges, }; -use crate::table::LookupTable; -use crate::util::power_of_randomness_from_instance; use eth_types::{Field, Word, U256}; pub(crate) use halo2_proofs::circuit::{Layouter, Value}; use halo2_proofs::{ @@ -63,36 +66,33 @@ where stored_expressions: Vec>, math_gadget_container: G, _marker: PhantomData, - power_of_randomness: [Expression; 31], + challenges: Challenges>, } -pub(crate) struct UnitTestMathGadgetBaseCircuit { +pub(crate) struct UnitTestMathGadgetBaseCircuit { size: usize, witnesses: Vec, - randomness: F, _marker: PhantomData, } -impl UnitTestMathGadgetBaseCircuit { - fn new(size: usize, witnesses: Vec, randomness: F) -> Self { +impl UnitTestMathGadgetBaseCircuit { + fn new(size: usize, witnesses: Vec) -> Self { UnitTestMathGadgetBaseCircuit { size, witnesses, - randomness, _marker: PhantomData, } } } -impl> Circuit for UnitTestMathGadgetBaseCircuit { - type Config = UnitTestMathGadgetBaseCircuitConfig; +impl> Circuit for UnitTestMathGadgetBaseCircuit { + type Config = (UnitTestMathGadgetBaseCircuitConfig, Challenges); type FloorPlanner = SimpleFloorPlanner; fn without_witnesses(&self) -> Self { UnitTestMathGadgetBaseCircuit { size: 0, witnesses: vec![], - randomness: F::from(123456u64), _marker: PhantomData, } } @@ -103,12 +103,17 @@ impl> Circuit for UnitTestMathGadgetBaseC let advices = [(); STEP_WIDTH].map(|_| meta.advice_column()); let step_curr = Step::new(meta, advices, 0, false); let step_next = Step::new(meta, advices, MAX_STEP_HEIGHT, true); - let power_of_randomness = power_of_randomness_from_instance(meta); - + let challenges = Challenges::construct(meta); + let challenges_exprs = challenges.exprs(meta); + let evm_word_powers_of_randomness = challenges_exprs.evm_word_powers_of_randomness(); + let lookup_input_powers_of_randomness = + challenges_exprs.lookup_input_powers_of_randomness(); let mut cb = ConstraintBuilder::new( step_curr.clone(), step_next, - &power_of_randomness, + &challenges_exprs, + &evm_word_powers_of_randomness, + &lookup_input_powers_of_randomness, ExecutionState::STOP, ); let math_gadget_container = G::configure_gadget_container(&mut cb); @@ -133,23 +138,26 @@ impl> Circuit for UnitTestMathGadgetBaseC let table_expressions = fixed_table.table_exprs(meta); vec![( column.expr(), - rlc::expr(&table_expressions, &power_of_randomness), + rlc::expr(&table_expressions, &lookup_input_powers_of_randomness), )] }); } } } - UnitTestMathGadgetBaseCircuitConfig:: { - q_usable, - fixed_table, - advices, - step: step_curr, - stored_expressions, - math_gadget_container, - _marker: PhantomData, - power_of_randomness, - } + ( + UnitTestMathGadgetBaseCircuitConfig:: { + q_usable, + fixed_table, + advices, + step: step_curr, + stored_expressions, + math_gadget_container, + _marker: PhantomData, + challenges: challenges_exprs, + }, + challenges, + ) } fn synthesize( @@ -157,15 +165,16 @@ impl> Circuit for UnitTestMathGadgetBaseC config: Self::Config, mut layouter: impl Layouter, ) -> Result<(), Error> { + let (config, challenges) = config; + let challenge_values = challenges.values(&mut layouter); layouter.assign_region( || "assign test container", |mut region| { let offset = 0; config.q_usable.enable(&mut region, offset)?; - let power_of_randomness = generate_power_of_randomness(self.randomness); let cached_region = &mut CachedRegion::<'_, '_, F>::new( &mut region, - power_of_randomness.try_into().unwrap(), + &challenge_values, config.advices.to_vec(), MAX_STEP_HEIGHT * 3, offset, @@ -229,14 +238,9 @@ pub(crate) fn test_math_gadget_container>( expected_success: bool, ) { const K: usize = 12; - let randomness = F::from(123456u64); - let power_of_randomness_instances: Vec> = generate_power_of_randomness(randomness) - .iter() - .map(|power_of_randomn: &F| vec![*power_of_randomn; (1 << K) - 64]) - .collect(); - let circuit = UnitTestMathGadgetBaseCircuit::::new(K, witnesses, randomness); - - let prover = MockProver::::run(K as u32, &circuit, power_of_randomness_instances).unwrap(); + let circuit = UnitTestMathGadgetBaseCircuit::::new(K, witnesses); + + let prover = MockProver::::run(K as u32, &circuit, vec![]).unwrap(); if expected_success { assert_eq!(prover.verify(), Ok(())); } else { diff --git a/zkevm-circuits/src/evm_circuit/util/memory_gadget.rs b/zkevm-circuits/src/evm_circuit/util/memory_gadget.rs index e6a6d5a48d..a06f97b63e 100644 --- a/zkevm-circuits/src/evm_circuit/util/memory_gadget.rs +++ b/zkevm-circuits/src/evm_circuit/util/memory_gadget.rs @@ -6,7 +6,7 @@ use crate::{ constraint_builder::ConstraintBuilder, from_bytes, math_gadget::{ConstantDivisionGadget, IsZeroGadget, MinMaxGadget, RangeCheckGadget}, - select, sum, Cell, MemoryAddress, Word, + select, sum, Cell, MemoryAddress, }, }, util::Expr, @@ -76,7 +76,7 @@ impl MemoryAddressGadget { memory_length: MemoryAddress, ) -> Self { let memory_length_is_zero = IsZeroGadget::construct(cb, sum::expr(&memory_length.cells)); - let memory_offset_bytes = cb.query_rlc(); + let memory_offset_bytes = cb.query_word_rlc(); let has_length = 1.expr() - memory_length_is_zero.expr(); cb.condition(has_length, |cb| { @@ -101,7 +101,6 @@ impl MemoryAddressGadget { offset: usize, memory_offset: U256, memory_length: U256, - randomness: F, ) -> Result { let memory_offset_bytes = memory_offset.to_le_bytes(); let memory_length_bytes = memory_length.to_le_bytes(); @@ -109,7 +108,7 @@ impl MemoryAddressGadget { self.memory_offset.assign( region, offset, - Value::known(Word::random_linear_combine(memory_offset_bytes, randomness)), + region.word_rlc(U256::from_little_endian(&memory_offset_bytes)), )?; self.memory_offset_bytes.assign( region, diff --git a/zkevm-circuits/src/state_circuit.rs b/zkevm-circuits/src/state_circuit.rs index 1cc63b6a6c..03fe5b581a 100644 --- a/zkevm-circuits/src/state_circuit.rs +++ b/zkevm-circuits/src/state_circuit.rs @@ -92,6 +92,7 @@ impl SubCircuitConfig for StateCircuitConfig { ) -> Self { let selector = meta.fixed_column(); let lookups = LookupsChip::configure(meta); + let power_of_randomness: [Expression; 31] = challenges.evm_word_powers_of_randomness(); let rw_counter = MpiChip::configure(meta, selector, rw_table.rw_counter, lookups); let tag = BinaryNumberChip::configure(meta, selector, Some(rw_table.tag)); @@ -103,7 +104,7 @@ impl SubCircuitConfig for StateCircuitConfig { selector, rw_table.storage_key, lookups, - challenges.evm_word_powers_of_randomness(), + power_of_randomness.clone(), ); let initial_value = meta.advice_column_in(SecondPhase); @@ -123,7 +124,7 @@ impl SubCircuitConfig for StateCircuitConfig { meta, sort_keys, lookups, - challenges.evm_word_powers_of_randomness(), + power_of_randomness.clone(), ); let config = Self { @@ -135,7 +136,7 @@ impl SubCircuitConfig for StateCircuitConfig { lexicographic_ordering, not_first_access: meta.advice_column(), lookups, - power_of_randomness: challenges.evm_word_powers_of_randomness(), + power_of_randomness, rw_table, mpt_table, }; @@ -591,7 +592,7 @@ mod state_circuit_stats { let mut implemented_states = Vec::new(); for state in ExecutionState::iter() { - let height = circuit.execution.get_step_height_option(state); + let height = circuit.0.execution.get_step_height_option(state); if height.is_some() { implemented_states.push(state); } diff --git a/zkevm-circuits/src/super_circuit.rs b/zkevm-circuits/src/super_circuit.rs index 4c3bb17478..29421c3b30 100644 --- a/zkevm-circuits/src/super_circuit.rs +++ b/zkevm-circuits/src/super_circuit.rs @@ -166,13 +166,14 @@ impl; 31] = array::from_fn(|i| { Expression::Constant(F::from(MOCK_RANDOMNESS).pow(&[1 + i as u64, 0, 0, 0])) }); let challenges = Challenges::mock( power_of_randomness[0].clone(), power_of_randomness[0].clone(), + power_of_randomness[0].clone(), ); let keccak_circuit = KeccakCircuitConfig::new( @@ -224,14 +225,14 @@ impl, block: &BlockContext, - randomness: F, + randomness: Value, ) -> Result<(), Error> { layouter.assign_region( || "block table", @@ -710,7 +710,7 @@ impl BlockTable { || format!("block table row {}", offset), *column, offset, - || Value::known(value), + || value, )?; } offset += 1; @@ -914,8 +914,8 @@ impl CopyTable { .map(|(value, _)| *value) .collect::>(); challenges - .evm_word() - .map(|evm_word_challenge| rlc::value(values.iter().rev(), evm_word_challenge)) + .keccak_input() + .map(|keccak_input| rlc::value(values.iter().rev(), keccak_input)) } else { Value::known(F::zero()) }; @@ -996,7 +996,7 @@ impl CopyTable { if is_read_step { Value::known(F::from(copy_step.value as u64)) } else { - value_acc = value_acc * challenges.evm_word() + value_acc = value_acc * challenges.keccak_input() + Value::known(F::from(copy_step.value as u64)); value_acc } diff --git a/zkevm-circuits/src/util.rs b/zkevm-circuits/src/util.rs index a5550fb6a3..82c8d0bbca 100644 --- a/zkevm-circuits/src/util.rs +++ b/zkevm-circuits/src/util.rs @@ -2,8 +2,9 @@ use halo2_proofs::{ arithmetic::FieldExt, circuit::{Layouter, Value}, - plonk::{Challenge, ConstraintSystem, Error, Expression, FirstPhase, VirtualCells}, - poly::Rotation, + plonk::{ + Challenge, ConstraintSystem, Error, Expression, FirstPhase, SecondPhase, VirtualCells, + }, }; use crate::table::TxLogFieldTag; @@ -28,50 +29,41 @@ pub(crate) fn random_linear_combine_word(bytes: [u8; 32], randomnes crate::evm_circuit::util::Word::random_linear_combine(bytes, randomness) } -/// Query N instances at current rotation and return their expressions. This -/// function is used to get the power of randomness (passed as -/// instances) in our tests. -pub fn power_of_randomness_from_instance( - meta: &mut ConstraintSystem, -) -> [Expression; N] { - // This gate is used just to get the array of expressions from the power of - // randomness instance column, so that later on we don't need to query - // columns everywhere, and can pass the power of randomness array - // expression everywhere. The gate itself doesn't add any constraints. - - let columns = [(); N].map(|_| meta.instance_column()); - query_expression(meta, |meta| { - columns.map(|column| meta.query_instance(column, Rotation::cur())) - }) -} - /// All challenges used in `SuperCircuit`. #[derive(Default, Clone, Copy, Debug)] pub struct Challenges { evm_word: T, keccak_input: T, + lookup_input: T, } impl Challenges { /// Construct `Challenges` by allocating challenges in specific phases. pub fn construct(meta: &mut ConstraintSystem) -> Self { #[cfg(test)] - let _dummy_col = meta.advice_column(); + let _dummy_cols = [ + meta.advice_column(), + meta.advice_column_in(SecondPhase), + meta.advice_column_in(halo2_proofs::plonk::ThirdPhase), + ]; Self { evm_word: meta.challenge_usable_after(FirstPhase), keccak_input: meta.challenge_usable_after(FirstPhase), + lookup_input: meta.challenge_usable_after(SecondPhase), } } /// Returns `Expression` of challenges from `ConstraintSystem`. pub fn exprs(&self, meta: &mut ConstraintSystem) -> Challenges> { - let [evm_word, keccak_input] = query_expression(meta, |meta| { - [self.evm_word, self.keccak_input].map(|challenge| meta.query_challenge(challenge)) + let [evm_word, keccak_input, lookup_input] = query_expression(meta, |meta| { + [self.evm_word, self.keccak_input, self.lookup_input] + .map(|challenge| meta.query_challenge(challenge)) }); Challenges { evm_word, keccak_input, + lookup_input, } } @@ -80,6 +72,7 @@ impl Challenges { Challenges { evm_word: layouter.get_challenge(self.evm_word), keccak_input: layouter.get_challenge(self.keccak_input), + lookup_input: layouter.get_challenge(self.lookup_input), } } } @@ -95,25 +88,46 @@ impl Challenges { self.keccak_input.clone() } - pub(crate) fn mock(evm_word: T, keccak_input: T) -> Self { + /// Returns challenge of `lookup_input`. + pub fn lookup_input(&self) -> T { + self.lookup_input.clone() + } + + /// Returns the challenges indexed by the challenge index + pub fn indexed(&self) -> [&T; 3] { + [&self.evm_word, &self.keccak_input, &self.lookup_input] + } + + pub(crate) fn mock(evm_word: T, keccak_input: T, lookup_input: T) -> Self { Self { evm_word, keccak_input, + lookup_input, } } } impl Challenges> { - /// Returns powers of randomness for word RLC encoding - pub fn evm_word_powers_of_randomness(&self) -> [Expression; S] { - std::iter::successors(self.evm_word.clone().into(), |power| { - (self.evm_word.clone() * power.clone()).into() + /// Returns powers of randomness + fn powers_of(base: Expression) -> [Expression; S] { + std::iter::successors(base.clone().into(), |power| { + (base.clone() * power.clone()).into() }) .take(S) .collect::>() .try_into() .unwrap() } + + /// Returns powers of randomness for word RLC encoding + pub fn evm_word_powers_of_randomness(&self) -> [Expression; S] { + Self::powers_of(self.evm_word.clone()) + } + + /// Returns powers of randomness for lookups + pub fn lookup_input_powers_of_randomness(&self) -> [Expression; S] { + Self::powers_of(self.lookup_input.clone()) + } } pub(crate) fn build_tx_log_address(index: u64, field_tag: TxLogFieldTag, log_id: u64) -> Address { diff --git a/zkevm-circuits/src/witness/block.rs b/zkevm-circuits/src/witness/block.rs index 9a78c20c9f..8a633ee6c5 100644 --- a/zkevm-circuits/src/witness/block.rs +++ b/zkevm-circuits/src/witness/block.rs @@ -6,6 +6,7 @@ use bus_mapping::{ Error, }; use eth_types::{Address, Field, ToLittleEndian, ToScalar, Word}; +use halo2_proofs::circuit::Value; use super::{step::step_convert, tx::tx_convert, Bytecode, ExecStep, RwMap, Transaction}; @@ -77,52 +78,58 @@ pub struct BlockContext { impl BlockContext { /// Assignments for block table - pub fn table_assignments(&self, randomness: F) -> Vec<[F; 3]> { + pub fn table_assignments(&self, randomness: Value) -> Vec<[Value; 3]> { [ vec![ [ - F::from(BlockContextFieldTag::Coinbase as u64), - F::zero(), - self.coinbase.to_scalar().unwrap(), + Value::known(F::from(BlockContextFieldTag::Coinbase as u64)), + Value::known(F::zero()), + Value::known(self.coinbase.to_scalar().unwrap()), ], [ - F::from(BlockContextFieldTag::Timestamp as u64), - F::zero(), - self.timestamp.to_scalar().unwrap(), + Value::known(F::from(BlockContextFieldTag::Timestamp as u64)), + Value::known(F::zero()), + Value::known(self.timestamp.to_scalar().unwrap()), ], [ - F::from(BlockContextFieldTag::Number as u64), - F::zero(), - self.number.to_scalar().unwrap(), + Value::known(F::from(BlockContextFieldTag::Number as u64)), + Value::known(F::zero()), + Value::known(self.number.to_scalar().unwrap()), ], [ - F::from(BlockContextFieldTag::Difficulty as u64), - F::zero(), - RandomLinearCombination::random_linear_combine( - self.difficulty.to_le_bytes(), - randomness, - ), + Value::known(F::from(BlockContextFieldTag::Difficulty as u64)), + Value::known(F::zero()), + randomness.map(|randomness| { + RandomLinearCombination::random_linear_combine( + self.difficulty.to_le_bytes(), + randomness, + ) + }), ], [ - F::from(BlockContextFieldTag::GasLimit as u64), - F::zero(), - F::from(self.gas_limit), + Value::known(F::from(BlockContextFieldTag::GasLimit as u64)), + Value::known(F::zero()), + Value::known(F::from(self.gas_limit)), ], [ - F::from(BlockContextFieldTag::BaseFee as u64), - F::zero(), - RandomLinearCombination::random_linear_combine( - self.base_fee.to_le_bytes(), - randomness, - ), + Value::known(F::from(BlockContextFieldTag::BaseFee as u64)), + Value::known(F::zero()), + randomness.map(|randomness| { + RandomLinearCombination::random_linear_combine( + self.base_fee.to_le_bytes(), + randomness, + ) + }), ], [ - F::from(BlockContextFieldTag::ChainId as u64), - F::zero(), - RandomLinearCombination::random_linear_combine( - self.chain_id.to_le_bytes(), - randomness, - ), + Value::known(F::from(BlockContextFieldTag::ChainId as u64)), + Value::known(F::zero()), + randomness.map(|randomness| { + RandomLinearCombination::random_linear_combine( + self.chain_id.to_le_bytes(), + randomness, + ) + }), ], ], { @@ -132,12 +139,14 @@ impl BlockContext { .enumerate() .map(|(idx, hash)| { [ - F::from(BlockContextFieldTag::BlockHash as u64), - (self.number - len_history + idx).to_scalar().unwrap(), - RandomLinearCombination::random_linear_combine( - hash.to_le_bytes(), - randomness, - ), + Value::known(F::from(BlockContextFieldTag::BlockHash as u64)), + Value::known((self.number - len_history + idx).to_scalar().unwrap()), + randomness.map(|randomness| { + RandomLinearCombination::random_linear_combine( + hash.to_le_bytes(), + randomness, + ) + }), ] }) .collect() @@ -168,8 +177,8 @@ pub fn block_convert( code_db: &bus_mapping::state_db::CodeDB, ) -> Result, Error> { Ok(Block { - randomness: F::from(0xcafeu64), // randomness: F::from(0x100), // Special value to reveal elements after RLC + randomness: F::from(0xcafeu64), context: block.into(), rws: RwMap::from(&block.container), txs: block diff --git a/zkevm-circuits/src/witness/rw.rs b/zkevm-circuits/src/witness/rw.rs index 8773c89043..9e092ff6a1 100644 --- a/zkevm-circuits/src/witness/rw.rs +++ b/zkevm-circuits/src/witness/rw.rs @@ -233,6 +233,10 @@ impl RwRow { .rev() .fold(F::zero(), |acc, value| acc * randomness + value) } + + pub(crate) fn rlc_value(&self, randomness: Value) -> Value { + randomness.map(|randomness| self.rlc(randomness)) + } } impl Rw {