From 0a0d7125133e23f72fdf25c49be52f65c115147d Mon Sep 17 00:00:00 2001 From: Ming Date: Tue, 20 Jun 2023 20:48:36 +0700 Subject: [PATCH] [word-lo-hi] evm circuit (#1411) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### Description This PR is based on https://github.com/privacy-scaling-explorations/zkevm-circuits/pull/1394 Need to merge https://github.com/privacy-scaling-explorations/zkevm-circuits/pull/1394 first before review this. ### Issue Link https://github.com/privacy-scaling-explorations/zkevm-circuits/issues/1379 ### Type of change - [x] Breaking change (fix or feature that would cause existing functionality to not work as expected) ### Contents - [x] fixed most of op compiling errors other than `callop.rs` and `begin_tx.rs`. - [x] fixed `callop.rs` and `begin_tx.rs` - [x] remove all compatible workaround `construct_new` under evm circuit - [x] unittest under evm circuit all pass `cargo test --features warn-unimplemented --features test --package zkevm-circuits --lib -- evm_circuit::execution::` - [x] fix few `word` gadgets generics to take `Word` instead of `T` to restrict it flexibility, since it's non sense to put type not related to word - [x] remove most of `deprecated` api under evm circuits - [x] add IntDecomposition type as an alternative to RandomLinearComposition, with base 256 ### Cell utilization on main branch vs on word-lo-hi branch #### Storage_1 ``` Main: +-----------------------------------+------------------------------+-------------------------+ | "storage_1" total_available_cells | "storage_1" total_used_cells | "storage_1" Utilization (%) | +-----------------------------------+------------------------------+-------------------------+ | 25480 | 6482 | 25.4 | +-----------------------------------+------------------------------+-------------------------+ Word-lo-hi +-----------------------------------+------------------------------+-----------------------------+ | "storage_1" total_available_cells | "storage_1" total_used_cells | "storage_1" Utilization (%) | +-----------------------------------+------------------------------+-----------------------------+ | 24080 | 7078 | 29.4 | +-----------------------------------+------------------------------+-----------------------------+ ``` #### Storage_2 ``` Main +-----------------------------------+------------------------------+-------------------------+ | "storage_2" total_available_cells | "storage_2" total_used_cells | "storage_2" Utilization | +-----------------------------------+------------------------------+-------------------------+ | 1456 | 467 | 32.1 | +-----------------------------------+------------------------------+-------------------------+ Word-lo-hi +-----------------------------------+------------------------------+-----------------------------+ | "storage_2" total_available_cells | "storage_2" total_used_cells | "storage_2" Utilization (%) | +-----------------------------------+------------------------------+-----------------------------+ | 1376 | 14 | 1.0 | +-----------------------------------+------------------------------+-----------------------------+ ``` #### Byte_lookup ``` Main 
+-------------------------------------+--------------------------------+---------------------------+ | "byte_lookup" total_available_cells | "byte_lookup" total_used_cells | "byte_lookup" Utilization | +-------------------------------------+--------------------------------+---------------------------+ | 8736 | 6786 | 77.7 | +-------------------------------------+--------------------------------+---------------------------+ Word-lo-hi +-------------------------------------+--------------------------------+-------------------------------+ | "byte_lookup" total_available_cells | "byte_lookup" total_used_cells | "byte_lookup" Utilization (%) | +-------------------------------------+--------------------------------+-------------------------------+ | 8256 | 6566 | 79.5 | +-------------------------------------+--------------------------------+-------------------------------+ ``` --------- Co-authored-by: Wu Sung-Ming --- zkevm-circuits/src/copy_circuit/dev.rs | 10 +- zkevm-circuits/src/copy_circuit/util.rs | 18 +- zkevm-circuits/src/evm_circuit.rs | 7 +- zkevm-circuits/src/evm_circuit/execution.rs | 15 +- .../src/evm_circuit/execution/add_sub.rs | 2 +- .../src/evm_circuit/execution/addmod.rs | 30 +- .../src/evm_circuit/execution/address.rs | 20 +- .../src/evm_circuit/execution/balance.rs | 44 +- .../src/evm_circuit/execution/begin_tx.rs | 352 ++++++++------- .../src/evm_circuit/execution/bitwise.rs | 39 +- .../src/evm_circuit/execution/block_ctx.rs | 148 +------ .../src/evm_circuit/execution/blockhash.rs | 30 +- .../src/evm_circuit/execution/byte.rs | 40 +- .../src/evm_circuit/execution/calldatacopy.rs | 45 +- .../src/evm_circuit/execution/calldataload.rs | 44 +- .../src/evm_circuit/execution/calldatasize.rs | 32 +- .../src/evm_circuit/execution/caller.rs | 32 +- .../src/evm_circuit/execution/callop.rs | 199 +++++---- .../src/evm_circuit/execution/callvalue.rs | 21 +- .../src/evm_circuit/execution/chainid.rs | 22 +- .../src/evm_circuit/execution/codecopy.rs | 23 +- .../src/evm_circuit/execution/codesize.rs | 24 +- .../src/evm_circuit/execution/comparator.rs | 84 ++-- .../src/evm_circuit/execution/create.rs | 239 +++++----- .../src/evm_circuit/execution/dummy.rs | 22 +- .../src/evm_circuit/execution/dup.rs | 17 +- .../src/evm_circuit/execution/end_tx.rs | 53 +-- .../execution/error_invalid_jump.rs | 33 +- .../evm_circuit/execution/error_oog_call.rs | 2 +- .../evm_circuit/execution/error_oog_exp.rs | 28 +- .../evm_circuit/execution/error_oog_log.rs | 10 +- .../execution/error_oog_memory_copy.rs | 49 ++- .../execution/error_oog_sload_sstore.rs | 89 ++-- .../execution/error_oog_static_memory.rs | 20 +- .../execution/error_return_data_oo_bound.rs | 36 +- .../execution/error_write_protection.rs | 46 +- .../src/evm_circuit/execution/exp.rs | 121 ++---- .../src/evm_circuit/execution/extcodecopy.rs | 69 +-- .../src/evm_circuit/execution/extcodehash.rs | 45 +- .../src/evm_circuit/execution/extcodesize.rs | 62 +-- .../src/evm_circuit/execution/gas.rs | 13 +- .../src/evm_circuit/execution/gasprice.rs | 18 +- .../src/evm_circuit/execution/is_zero.rs | 29 +- .../src/evm_circuit/execution/jump.rs | 31 +- .../src/evm_circuit/execution/jumpi.rs | 30 +- .../src/evm_circuit/execution/logs.rs | 58 ++- .../src/evm_circuit/execution/memory.rs | 22 +- .../src/evm_circuit/execution/msize.rs | 24 +- .../src/evm_circuit/execution/mul_div_mod.rs | 63 +-- .../src/evm_circuit/execution/mulmod.rs | 76 ++-- .../src/evm_circuit/execution/not.rs | 29 +- .../src/evm_circuit/execution/origin.rs | 29 +- .../src/evm_circuit/execution/pc.rs | 13 +- .../src/evm_circuit/execution/pop.rs | 18 +- .../src/evm_circuit/execution/push.rs | 5 +- .../evm_circuit/execution/return_revert.rs | 62 ++- .../evm_circuit/execution/returndatacopy.rs | 56 +-- .../evm_circuit/execution/returndatasize.rs | 32 +- .../src/evm_circuit/execution/sar.rs | 60 +-- .../src/evm_circuit/execution/sdiv_smod.rs | 71 +-- .../src/evm_circuit/execution/selfbalance.rs | 44 +- .../src/evm_circuit/execution/sha3.rs | 54 ++- .../src/evm_circuit/execution/shl_shr.rs | 93 ++-- .../execution/signed_comparator.rs | 43 +- .../src/evm_circuit/execution/signextend.rs | 70 +-- .../src/evm_circuit/execution/sload.rs | 77 ++-- .../src/evm_circuit/execution/sstore.rs | 196 ++++----- .../src/evm_circuit/execution/stop.rs | 9 +- .../src/evm_circuit/execution/swap.rs | 25 +- zkevm-circuits/src/evm_circuit/param.rs | 3 + zkevm-circuits/src/evm_circuit/step.rs | 30 +- zkevm-circuits/src/evm_circuit/table.rs | 23 +- zkevm-circuits/src/evm_circuit/util.rs | 59 +-- .../src/evm_circuit/util/common_gadget.rs | 168 +++---- .../evm_circuit/util/constraint_builder.rs | 409 +++--------------- .../src/evm_circuit/util/math_gadget.rs | 2 +- .../evm_circuit/util/math_gadget/abs_word.rs | 32 +- .../evm_circuit/util/math_gadget/add_words.rs | 24 +- .../evm_circuit/util/math_gadget/byte_size.rs | 4 +- .../evm_circuit/util/math_gadget/cmp_words.rs | 4 +- .../util/math_gadget/is_equal_word.rs | 16 +- .../util/math_gadget/is_zero_word.rs | 15 +- .../evm_circuit/util/math_gadget/lt_word.rs | 96 +--- .../util/math_gadget/min_max_word.rs | 68 +-- .../evm_circuit/util/math_gadget/modulo.rs | 49 +-- .../util/math_gadget/mul_add_words.rs | 32 +- .../util/math_gadget/mul_add_words512.rs | 29 +- .../util/math_gadget/mul_word_u64.rs | 14 +- .../src/evm_circuit/util/math_gadget/rlp.rs | 90 ++-- .../src/evm_circuit/util/memory_gadget.rs | 78 ++-- zkevm-circuits/src/super_circuit.rs | 6 +- zkevm-circuits/src/table.rs | 2 +- zkevm-circuits/src/table/block_table.rs | 3 +- zkevm-circuits/src/table/bytecode_table.rs | 3 +- zkevm-circuits/src/table/copy_table.rs | 41 +- zkevm-circuits/src/table/rw_table.rs | 2 +- zkevm-circuits/src/table/tx_table.rs | 18 +- zkevm-circuits/src/util.rs | 1 + zkevm-circuits/src/util/int_decomposition.rs | 108 +++++ zkevm-circuits/src/util/word.rs | 83 ++-- zkevm-circuits/src/witness/block.rs | 30 +- zkevm-circuits/src/witness/bytecode.rs | 18 +- zkevm-circuits/src/witness/tx.rs | 32 +- 103 files changed, 2327 insertions(+), 2837 deletions(-) create mode 100644 zkevm-circuits/src/util/int_decomposition.rs diff --git a/zkevm-circuits/src/copy_circuit/dev.rs b/zkevm-circuits/src/copy_circuit/dev.rs index 06e87e93e0..85f0f71b04 100644 --- a/zkevm-circuits/src/copy_circuit/dev.rs +++ b/zkevm-circuits/src/copy_circuit/dev.rs @@ -57,7 +57,6 @@ impl Circuit for CopyCircuit { &self.external_data.txs, self.external_data.max_txs, self.external_data.max_calldata, - &challenge_values, )?; config.0.rw_table.load( @@ -66,11 +65,10 @@ impl Circuit for CopyCircuit { self.external_data.max_rws, )?; - config.0.bytecode_table.load( - &mut layouter, - self.external_data.bytecodes.values(), - &challenge_values, - )?; + config + .0 + .bytecode_table + .load(&mut layouter, self.external_data.bytecodes.values())?; self.synthesize_sub(&config.0, &challenge_values, &mut layouter) } } diff --git a/zkevm-circuits/src/copy_circuit/util.rs b/zkevm-circuits/src/copy_circuit/util.rs index 87d5056949..24cce0f3f4 100644 --- a/zkevm-circuits/src/copy_circuit/util.rs +++ b/zkevm-circuits/src/copy_circuit/util.rs @@ -1,22 +1,12 @@ -use crate::evm_circuit::util::rlc; +use crate::util::word::Word; use bus_mapping::circuit_input_builder::NumberOrHash; use eth_types::Field; use halo2_proofs::circuit::Value; /// Encode the type `NumberOrHash` into a field element -pub fn number_or_hash_to_field(v: &NumberOrHash, challenge: Value) -> Value { +pub fn number_or_hash_to_word(v: &NumberOrHash) -> Word> { match v { - NumberOrHash::Number(n) => Value::known(F::from(*n as u64)), - NumberOrHash::Hash(h) => { - // since code hash in the bytecode table is represented in - // the little-endian form, we reverse the big-endian bytes - // of H256. - let le_bytes = { - let mut b = h.to_fixed_bytes(); - b.reverse(); - b - }; - challenge.map(|challenge| rlc::value(&le_bytes, challenge)) - } + NumberOrHash::Number(n) => Word::from(*n as u64).into_value(), + NumberOrHash::Hash(h) => Word::from(*h).into_value(), } } diff --git a/zkevm-circuits/src/evm_circuit.rs b/zkevm-circuits/src/evm_circuit.rs index 0b0f1f0931..09c968cad7 100644 --- a/zkevm-circuits/src/evm_circuit.rs +++ b/zkevm-circuits/src/evm_circuit.rs @@ -411,7 +411,6 @@ impl Circuit for EvmCircuit { &block.txs, block.circuits_params.max_txs, block.circuits_params.max_calldata, - &challenges, )?; block.rws.check_rw_counter_sanity(); config.rw_table.load( @@ -421,10 +420,8 @@ impl Circuit for EvmCircuit { )?; config .bytecode_table - .load(&mut layouter, block.bytecodes.values(), &challenges)?; - config - .block_table - .load(&mut layouter, &block.context, challenges.evm_word())?; + .load(&mut layouter, block.bytecodes.values())?; + config.block_table.load(&mut layouter, &block.context)?; config.copy_table.load(&mut layouter, block, &challenges)?; config .keccak_table diff --git a/zkevm-circuits/src/evm_circuit/execution.rs b/zkevm-circuits/src/evm_circuit/execution.rs index 7766784f7a..1ce419f635 100644 --- a/zkevm-circuits/src/evm_circuit/execution.rs +++ b/zkevm-circuits/src/evm_circuit/execution.rs @@ -111,14 +111,13 @@ mod sstore; mod stop; mod swap; -use self::sha3::Sha3Gadget; +use self::{block_ctx::BlockCtxGadget, sha3::Sha3Gadget}; use add_sub::AddSubGadget; use addmod::AddModGadget; use address::AddressGadget; use balance::BalanceGadget; use begin_tx::BeginTxGadget; use bitwise::BitwiseGadget; -use block_ctx::{BlockCtxU160Gadget, BlockCtxU256Gadget, BlockCtxU64Gadget}; use blockhash::BlockHashGadget; use byte::ByteGadget; use calldatacopy::CallDataCopyGadget; @@ -281,9 +280,7 @@ pub struct ExecutionConfig { stop_gadget: Box>, swap_gadget: Box>, blockhash_gadget: Box>, - block_ctx_u64_gadget: Box>, - block_ctx_u160_gadget: Box>, - block_ctx_u256_gadget: Box>, + block_ctx_gadget: Box>, // error gadgets error_oog_call: Box>, error_oog_constant: Box>, @@ -548,9 +545,7 @@ impl ExecutionConfig { sstore_gadget: configure_gadget!(), stop_gadget: configure_gadget!(), swap_gadget: configure_gadget!(), - block_ctx_u64_gadget: configure_gadget!(), - block_ctx_u160_gadget: configure_gadget!(), - block_ctx_u256_gadget: configure_gadget!(), + block_ctx_gadget: configure_gadget!(), // error gadgets error_oog_constant: configure_gadget!(), error_oog_static_memory_gadget: configure_gadget!(), @@ -1216,9 +1211,7 @@ impl ExecutionConfig { ExecutionState::SAR => assign_exec_step!(self.sar_gadget), ExecutionState::SCMP => assign_exec_step!(self.signed_comparator_gadget), ExecutionState::SDIV_SMOD => assign_exec_step!(self.sdiv_smod_gadget), - ExecutionState::BLOCKCTXU64 => assign_exec_step!(self.block_ctx_u64_gadget), - ExecutionState::BLOCKCTXU160 => assign_exec_step!(self.block_ctx_u160_gadget), - ExecutionState::BLOCKCTXU256 => assign_exec_step!(self.block_ctx_u256_gadget), + ExecutionState::BLOCKCTX => assign_exec_step!(self.block_ctx_gadget), ExecutionState::BLOCKHASH => assign_exec_step!(self.blockhash_gadget), ExecutionState::SELFBALANCE => assign_exec_step!(self.selfbalance_gadget), // dummy gadgets diff --git a/zkevm-circuits/src/evm_circuit/execution/add_sub.rs b/zkevm-circuits/src/evm_circuit/execution/add_sub.rs index 72d6d55164..90246abe36 100644 --- a/zkevm-circuits/src/evm_circuit/execution/add_sub.rs +++ b/zkevm-circuits/src/evm_circuit/execution/add_sub.rs @@ -41,7 +41,7 @@ impl ExecutionGadget for AddSubGadget { let a = cb.query_word32(); let b = cb.query_word32(); let c = cb.query_word32(); - let add_words = AddWordsGadget::construct_new(cb, [a.clone(), b.clone()], c.clone()); + let add_words = AddWordsGadget::construct(cb, [a.clone(), b.clone()], c.clone()); // Swap a and c if opcode is SUB let is_sub = PairSelectGadget::construct( diff --git a/zkevm-circuits/src/evm_circuit/execution/addmod.rs b/zkevm-circuits/src/evm_circuit/execution/addmod.rs index 1fe9fa5ec2..03a65af995 100644 --- a/zkevm-circuits/src/evm_circuit/execution/addmod.rs +++ b/zkevm-circuits/src/evm_circuit/execution/addmod.rs @@ -23,7 +23,7 @@ use crate::{ }; use bus_mapping::evm::OpcodeId; -use eth_types::{Field, ToLittleEndian, U256, U512}; +use eth_types::{Field, U256, U512}; use halo2_proofs::{circuit::Value, plonk::Error}; #[derive(Clone, Debug)] @@ -69,11 +69,11 @@ impl ExecutionGadget for AddModGadget { let a_reduced = cb.query_word32(); let d = cb.query_word32(); - let n_is_zero = IsZeroWordGadget::construct(cb, n.clone()); + let n_is_zero = IsZeroWordGadget::construct(cb, &n); // 1. check k * N + a_reduced == a without overflow let muladd_k_n_areduced = - MulAddWordsGadget::construct_new(cb, [&k, &n.clone(), &a_reduced, &a]); + MulAddWordsGadget::construct(cb, [&k, &n.clone(), &a_reduced, &a]); cb.require_zero( "k * N + a_reduced does not overflow", muladd_k_n_areduced.overflow(), @@ -82,7 +82,7 @@ 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_word32(); - AddWordsGadget::construct_new(cb, [a_reduced.clone(), b.clone()], sum) + AddWordsGadget::construct(cb, [a_reduced.clone(), b.clone()], sum) }; let sum_areduced_b_overflow = cb.query_word32(); let muladd_d_n_r = MulAddWords512Gadget::construct( @@ -162,9 +162,9 @@ impl ExecutionGadget for AddModGadget { let [mut r, n, b, a] = [3, 2, 1, 0].map(|index| block.get_rws(step, index).stack_value()); // assing a,b & n stack values - self.a.assign(region, offset, Some(a.to_le_bytes()))?; - self.b.assign(region, offset, Some(b.to_le_bytes()))?; - self.n.assign(region, offset, Some(n.to_le_bytes()))?; + self.a.assign_u256(region, offset, a)?; + self.b.assign_u256(region, offset, b)?; + self.n.assign_u256(region, offset, n)?; // compute a_reduced,k,d,a_reduced_plus_b,a_reduced_plus_b_overflow,r values let a_reduced; @@ -196,11 +196,10 @@ impl ExecutionGadget for AddModGadget { // rest of values and gadgets - self.r.assign(region, offset, Some(r.to_le_bytes()))?; - self.k.assign(region, offset, Some(k.to_le_bytes()))?; - self.d.assign(region, offset, Some(d.to_le_bytes()))?; - self.a_reduced - .assign(region, offset, Some(a_reduced.to_le_bytes()))?; + self.r.assign_u256(region, offset, r)?; + self.k.assign_u256(region, offset, k)?; + self.d.assign_u256(region, offset, d)?; + self.a_reduced.assign_u256(region, offset, a_reduced)?; self.muladd_k_n_areduced .assign(region, offset, [k, n, a_reduced, a])?; @@ -208,11 +207,8 @@ impl ExecutionGadget for AddModGadget { self.sum_areduced_b .assign(region, offset, [a_reduced, b], a_reduced_plus_b)?; - self.sum_areduced_b_overflow.assign( - region, - offset, - Some(a_reduced_plus_b_overflow.to_le_bytes()), - )?; + self.sum_areduced_b_overflow + .assign_u256(region, offset, a_reduced_plus_b_overflow)?; self.muladd_d_n_r.assign( region, offset, diff --git a/zkevm-circuits/src/evm_circuit/execution/address.rs b/zkevm-circuits/src/evm_circuit/execution/address.rs index 7057d67893..896f0d291b 100644 --- a/zkevm-circuits/src/evm_circuit/execution/address.rs +++ b/zkevm-circuits/src/evm_circuit/execution/address.rs @@ -5,21 +5,24 @@ use crate::{ util::{ common_gadget::SameContextGadget, constraint_builder::{EVMConstraintBuilder, StepStateTransition, Transition::Delta}, - AccountAddress, CachedRegion, + CachedRegion, }, witness::{Block, Call, ExecStep, Transaction}, }, table::CallContextFieldTag, - util::{word::WordExpr, Expr}, + util::{ + word::{WordCell, WordExpr}, + Expr, + }, }; use bus_mapping::evm::OpcodeId; -use eth_types::{Field, ToAddress, ToLittleEndian}; +use eth_types::{Field, ToAddress}; use halo2_proofs::plonk::Error; #[derive(Clone, Debug)] pub(crate) struct AddressGadget { same_context: SameContextGadget, - address: AccountAddress, + address: WordCell, } impl ExecutionGadget for AddressGadget { @@ -28,7 +31,7 @@ impl ExecutionGadget for AddressGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::ADDRESS; fn configure(cb: &mut EVMConstraintBuilder) -> Self { - let address = cb.query_account_address(); + let address = cb.query_word_unchecked(); // Lookup callee address in call context. cb.call_context_lookup_read(None, CallContextFieldTag::CalleeAddress, address.to_word()); @@ -66,11 +69,8 @@ impl ExecutionGadget for AddressGadget { let address = block.get_rws(step, 1).stack_value(); debug_assert_eq!(call.address, address.to_address()); - self.address.assign( - region, - offset, - Some(address.to_le_bytes()[..20].try_into().unwrap()), - )?; + self.address + .assign_h160(region, offset, address.to_address())?; Ok(()) } diff --git a/zkevm-circuits/src/evm_circuit/execution/balance.rs b/zkevm-circuits/src/evm_circuit/execution/balance.rs index 2b20681fc3..ff9ff8e0bc 100644 --- a/zkevm-circuits/src/evm_circuit/execution/balance.rs +++ b/zkevm-circuits/src/evm_circuit/execution/balance.rs @@ -8,29 +8,29 @@ use crate::{ ConstrainBuilderCommon, EVMConstraintBuilder, ReversionInfo, StepStateTransition, Transition::Delta, }, - math_gadget::IsZeroGadget, - not, select, CachedRegion, Cell, Word, + math_gadget::IsZeroWordGadget, + not, select, AccountAddress, CachedRegion, Cell, }, witness::{Block, Call, ExecStep, Transaction}, }, table::{AccountFieldTag, CallContextFieldTag}, util::{ - word::{Word32Cell, WordExpr}, + word::{Word, Word32Cell, WordCell, WordExpr}, Expr, }, }; -use eth_types::{evm_types::GasCost, Field, ToLittleEndian}; +use eth_types::{evm_types::GasCost, Field, ToWord}; use halo2_proofs::{circuit::Value, plonk::Error}; #[derive(Clone, Debug)] pub(crate) struct BalanceGadget { same_context: SameContextGadget, - address_word: Word, + address: AccountAddress, reversion_info: ReversionInfo, tx_id: Cell, is_warm: Cell, - code_hash: Word32Cell, - not_exists: IsZeroGadget, + code_hash: WordCell, + not_exists: IsZeroWordGadget>, balance: Word32Cell, } @@ -40,31 +40,35 @@ impl ExecutionGadget for BalanceGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::BALANCE; fn configure(cb: &mut EVMConstraintBuilder) -> Self { - let address = cb.query_word_rlc(); + let address = cb.query_account_address(); cb.stack_pop_word(address.to_word()); let tx_id = cb.call_context(None, CallContextFieldTag::TxId); let mut reversion_info = cb.reversion_info_read(None); let is_warm = cb.query_bool(); - cb.account_access_list_write( + cb.account_access_list_write_unchecked( tx_id.expr(), - address.expr(), + address.to_word(), 1.expr(), is_warm.expr(), Some(&mut reversion_info), ); - let code_hash = cb.query_word32(); + let code_hash = cb.query_word_unchecked(); // For non-existing accounts the code_hash must be 0 in the rw_table. cb.account_read_word( - address.expr(), + address.to_word(), AccountFieldTag::CodeHash, code_hash.to_word(), ); - let not_exists = IsZeroGadget::construct(cb, code_hash.expr()); + let not_exists = IsZeroWordGadget::construct(cb, &code_hash); let exists = not::expr(not_exists.expr()); let balance = cb.query_word32(); cb.condition(exists.expr(), |cb| { - cb.account_read_word(address.expr(), AccountFieldTag::Balance, balance.to_word()); + cb.account_read_word( + address.to_word(), + AccountFieldTag::Balance, + balance.to_word(), + ); }); cb.condition(not_exists.expr(), |cb| { cb.require_zero_word("balance is zero when non_exists", balance.to_word()); @@ -92,7 +96,7 @@ impl ExecutionGadget for BalanceGadget { Self { same_context, - address_word: address, + address, reversion_info, tx_id, is_warm, @@ -114,8 +118,7 @@ impl ExecutionGadget for BalanceGadget { self.same_context.assign_exec_step(region, offset, step)?; let address = block.get_rws(step, 0).stack_value(); - self.address_word - .assign(region, offset, Some(address.to_le_bytes()))?; + self.address.assign_u256(region, offset, address)?; self.tx_id .assign(region, offset, Value::known(F::from(tx.id as u64)))?; @@ -133,16 +136,15 @@ impl ExecutionGadget for BalanceGadget { let code_hash = block.get_rws(step, 5).account_value_pair().0; self.code_hash - .assign(region, offset, Some(code_hash.to_le_bytes()))?; + .assign_u256(region, offset, code_hash.to_word())?; self.not_exists - .assign_value(region, offset, region.word_rlc(code_hash))?; + .assign_value(region, offset, Value::known(Word::from(code_hash)))?; let balance = if code_hash.is_zero() { eth_types::Word::zero() } else { block.get_rws(step, 6).account_value_pair().0 }; - self.balance - .assign(region, offset, Some(balance.to_le_bytes()))?; + self.balance.assign_u256(region, offset, balance)?; Ok(()) } diff --git a/zkevm-circuits/src/evm_circuit/execution/begin_tx.rs b/zkevm-circuits/src/evm_circuit/execution/begin_tx.rs index ce90c49793..45232e43be 100644 --- a/zkevm-circuits/src/evm_circuit/execution/begin_tx.rs +++ b/zkevm-circuits/src/evm_circuit/execution/begin_tx.rs @@ -1,7 +1,7 @@ use crate::{ evm_circuit::{ execution::ExecutionGadget, - param::{N_BYTES_ACCOUNT_ADDRESS, N_BYTES_GAS, N_BYTES_U64, N_BYTES_WORD}, + param::{N_BYTES_ACCOUNT_ADDRESS, N_BYTES_GAS, N_BYTES_U64}, step::ExecutionState, util::{ and, @@ -12,34 +12,41 @@ use crate::{ }, is_precompiled, math_gadget::{ - ConstantDivisionGadget, ContractCreateGadget, IsEqualGadget, IsZeroGadget, + ConstantDivisionGadget, ContractCreateGadget, IsEqualWordGadget, IsZeroWordGadget, MulWordByU64Gadget, RangeCheckGadget, }, - not, or, select, CachedRegion, Cell, StepRws, + not, or, select, AccountAddress, CachedRegion, Cell, StepRws, }, witness::{Block, Call, ExecStep, Transaction}, }, table::{ AccountFieldTag, BlockContextFieldTag, CallContextFieldTag, TxFieldTag as TxContextFieldTag, }, - util::{word::Word32Cell, Expr}, + util::{ + word::{Word, Word32Cell, WordCell, WordExpr}, + Expr, + }, }; -use eth_types::{evm_types::GasCost, Field, ToLittleEndian, ToScalar}; +use bus_mapping::state_db::CodeDB; +use eth_types::{evm_types::GasCost, Field, ToWord, U256}; use ethers_core::utils::{get_contract_address, keccak256}; -use gadgets::util::expr_from_bytes; -use halo2_proofs::{circuit::Value, plonk::Error}; +use halo2_proofs::{ + circuit::Value, + plonk::{Error, Expression}, +}; #[derive(Clone, Debug)] pub(crate) struct BeginTxGadget { + // tx_id is query in current scope. The range should be determined here tx_id: Cell, tx_nonce: Cell, tx_gas: Cell, tx_gas_price: Word32Cell, mul_gas_fee_by_gas: MulWordByU64Gadget, - tx_caller_address: Cell, - tx_caller_address_is_zero: IsZeroGadget, - tx_callee_address: Cell, - call_callee_address: Cell, + tx_caller_address: WordCell, + tx_caller_address_is_zero: IsZeroWordGadget>, + tx_callee_address: WordCell, + call_callee_address: AccountAddress, tx_is_create: Cell, tx_value: Word32Cell, tx_call_data_length: Cell, @@ -48,14 +55,14 @@ pub(crate) struct BeginTxGadget { reversion_info: ReversionInfo, sufficient_gas_left: RangeCheckGadget, transfer_with_gas_fee: TransferWithGasFeeGadget, - phase2_code_hash: Cell, - is_empty_code_hash: IsEqualGadget, - caller_nonce_hash_bytes: [Cell; N_BYTES_WORD], + code_hash: WordCell, + is_empty_code_hash: IsEqualWordGadget>, Word>>, + caller_nonce_hash_bytes: Word32Cell, create: ContractCreateGadget, - callee_not_exists: IsZeroGadget, + callee_not_exists: IsZeroWordGadget>, is_caller_callee_equal: Cell, // EIP-3651 (Warm COINBASE) - coinbase: Cell, + coinbase: WordCell, // Caller, callee and a list addresses are added to the access list before // coinbase, and may be duplicate. // @@ -71,47 +78,49 @@ impl ExecutionGadget for BeginTxGadget { // Use rw_counter of the step which triggers next call as its call_id. let call_id = cb.curr.state.rw_counter.clone(); - let tx_id = cb.query_cell(); - cb.call_context_lookup( - 1.expr(), + let tx_id = cb.query_cell(); // already constrain `if step_first && tx_id = 1` and `tx_id += 1` at EndTx + cb.call_context_lookup_write( Some(call_id.expr()), CallContextFieldTag::TxId, - tx_id.expr(), + Word::from_lo_unchecked(tx_id.expr()), ); // rwc_delta += 1 - let mut reversion_info = cb.reversion_info_write(None); // rwc_delta += 2 - cb.call_context_lookup( - 1.expr(), + let mut reversion_info = cb.reversion_info_write_unchecked(None); // rwc_delta += 2 + cb.call_context_lookup_write( Some(call_id.expr()), CallContextFieldTag::IsSuccess, - reversion_info.is_persistent(), + Word::from_lo_unchecked(reversion_info.is_persistent()), ); // rwc_delta += 1 - let [tx_nonce, tx_gas, tx_caller_address, tx_callee_address, tx_is_create, tx_call_data_length, tx_call_data_gas_cost] = - [ - TxContextFieldTag::Nonce, - TxContextFieldTag::Gas, - TxContextFieldTag::CallerAddress, - TxContextFieldTag::CalleeAddress, - TxContextFieldTag::IsCreate, - TxContextFieldTag::CallDataLength, - TxContextFieldTag::CallDataGasCost, - ] - .map(|field_tag| cb.tx_context(tx_id.expr(), field_tag, None)); - let tx_caller_address_is_zero = IsZeroGadget::construct(cb, tx_caller_address.expr()); + let [tx_nonce, tx_gas, tx_is_create, tx_call_data_length, tx_call_data_gas_cost] = [ + TxContextFieldTag::Nonce, + TxContextFieldTag::Gas, + TxContextFieldTag::IsCreate, + TxContextFieldTag::CallDataLength, + TxContextFieldTag::CallDataGasCost, + ] + .map(|field_tag| cb.tx_context(tx_id.expr(), field_tag, None)); + let [tx_gas_price, tx_value] = [TxContextFieldTag::GasPrice, TxContextFieldTag::Value] + .map(|field_tag| cb.tx_context_as_word32(tx_id.expr(), field_tag, None)); + + let [tx_caller_address, tx_callee_address] = [ + TxContextFieldTag::CallerAddress, + TxContextFieldTag::CalleeAddress, + ] + .map(|field_tag| cb.tx_context_as_word(tx_id.expr(), field_tag, None)); + + let tx_caller_address_is_zero = IsZeroWordGadget::construct(cb, &tx_caller_address); cb.require_equal( "CallerAddress != 0 (not a padding tx)", tx_caller_address_is_zero.expr(), false.expr(), ); - let [tx_gas_price, tx_value] = [TxContextFieldTag::GasPrice, TxContextFieldTag::Value] - .map(|field_tag| cb.tx_context_as_word(tx_id.expr(), field_tag, None)); - let call_callee_address = cb.query_cell(); + let call_callee_address = cb.query_account_address(); cb.condition(not::expr(tx_is_create.expr()), |cb| { - cb.require_equal( + cb.require_equal_word( "Tx to non-zero address", - tx_callee_address.expr(), - call_callee_address.expr(), + tx_callee_address.to_word(), + call_callee_address.to_word(), ); }); @@ -122,11 +131,11 @@ impl ExecutionGadget for BeginTxGadget { // Increase caller's nonce. // (tx caller's nonce always increases even tx ends with error) - cb.account_write( - tx_caller_address.expr(), + cb.account_write_word( + tx_caller_address.to_word(), AccountFieldTag::Nonce, - tx_nonce.expr() + 1.expr(), - tx_nonce.expr(), + Word::from_lo_unchecked(tx_nonce.expr() + 1.expr()), + Word::from_lo_unchecked(tx_nonce.expr()), None, ); // rwc_delta += 1 @@ -134,7 +143,7 @@ impl ExecutionGadget for BeginTxGadget { // transaction format) // Calculate transaction gas fee let mul_gas_fee_by_gas = - MulWordByU64Gadget::construct(cb, tx_gas_price.clone().into(), tx_gas.expr()); + MulWordByU64Gadget::construct(cb, tx_gas_price.clone(), tx_gas.expr()); let tx_call_data_word_length = ConstantDivisionGadget::construct(cb, tx_call_data_length.expr() + 31.expr(), 32); @@ -161,17 +170,17 @@ impl ExecutionGadget for BeginTxGadget { let sufficient_gas_left = RangeCheckGadget::construct(cb, gas_left.clone()); // Prepare access list of caller and callee - cb.account_access_list_write( + cb.account_access_list_write_unchecked( tx_id.expr(), - tx_caller_address.expr(), + tx_caller_address.to_word(), 1.expr(), 0.expr(), None, ); // rwc_delta += 1 let is_caller_callee_equal = cb.query_bool(); - cb.account_access_list_write( + cb.account_access_list_write_unchecked( tx_id.expr(), - tx_callee_address.expr(), + tx_callee_address.to_word(), 1.expr(), // No extra constraint being used here. // Correctness will be enforced in build_tx_access_list_account_constraints @@ -180,22 +189,26 @@ impl ExecutionGadget for BeginTxGadget { ); // rwc_delta += 1 // Query coinbase address. - let coinbase = cb.query_cell(); + let coinbase = cb.query_word_unchecked(); let is_coinbase_warm = cb.query_bool(); - cb.block_lookup(BlockContextFieldTag::Coinbase.expr(), None, coinbase.expr()); - cb.account_access_list_write( + cb.block_lookup_word( + BlockContextFieldTag::Coinbase.expr(), + None, + coinbase.to_word(), + ); + cb.account_access_list_write_unchecked( tx_id.expr(), - coinbase.expr(), + coinbase.to_word(), 1.expr(), is_coinbase_warm.expr(), None, ); // rwc_delta += 1 // Read code_hash of callee - let phase2_code_hash = cb.query_cell_phase2(); + let code_hash = cb.query_word_unchecked(); let is_empty_code_hash = - IsEqualGadget::construct(cb, phase2_code_hash.expr(), cb.empty_code_hash_rlc()); - let callee_not_exists = IsZeroGadget::construct(cb, phase2_code_hash.expr()); + IsEqualWordGadget::construct(cb, &code_hash.to_word(), &cb.empty_code_hash_word()); + let callee_not_exists = IsZeroWordGadget::construct(cb, &code_hash); // no_callee_code is true when the account exists and has empty // code hash, or when the account doesn't exist (which we encode with // code_hash = 0). @@ -203,37 +216,43 @@ impl ExecutionGadget for BeginTxGadget { // TODO: And not precompile cb.condition(not::expr(tx_is_create.expr()), |cb| { - cb.account_read( - tx_callee_address.expr(), + cb.account_read_word( + tx_callee_address.to_word(), AccountFieldTag::CodeHash, - phase2_code_hash.expr(), + code_hash.to_word(), ); // rwc_delta += 1 }); // Transfer value from caller to callee, creating account if necessary. - let transfer_with_gas_fee = TransferWithGasFeeGadget::construct_new( + let transfer_with_gas_fee = TransferWithGasFeeGadget::construct( cb, - tx_caller_address.expr(), - tx_callee_address.expr(), + tx_caller_address.to_word(), + tx_callee_address.to_word(), not::expr(callee_not_exists.expr()), or::expr([tx_is_create.expr(), callee_not_exists.expr()]), - tx_value.clone().into(), + tx_value.clone(), mul_gas_fee_by_gas.product().clone(), &mut reversion_info, ); - let caller_nonce_hash_bytes = array_init::array_init(|_| cb.query_byte()); + let caller_nonce_hash_bytes = cb.query_word32(); let create = ContractCreateGadget::construct(cb); - cb.require_equal( + cb.require_equal_word( "tx caller address equivalence", - tx_caller_address.expr(), - create.caller_address(), + tx_caller_address.to_word(), + create.caller_address_word(), ); cb.condition(tx_is_create.expr(), |cb| { - cb.require_equal( + cb.require_equal_word( "call callee address equivalence", - call_callee_address.expr(), - expr_from_bytes(&caller_nonce_hash_bytes[0..N_BYTES_ACCOUNT_ADDRESS]), + call_callee_address.to_word(), + AccountAddress::::new( + caller_nonce_hash_bytes.limbs[0..N_BYTES_ACCOUNT_ADDRESS] + .to_vec() + .try_into() + .unwrap(), + ) + .to_word(), ); }); cb.require_equal( @@ -244,48 +263,53 @@ impl ExecutionGadget for BeginTxGadget { // 1. Handle contract creation transaction. cb.condition(tx_is_create.expr(), |cb| { - let output_rlc = cb.word_rlc::( - caller_nonce_hash_bytes - .iter() - .map(Expr::expr) - .collect::>() - .try_into() - .unwrap(), + cb.keccak_table_lookup_word( + create.input_rlc(cb), + create.input_length(), + caller_nonce_hash_bytes.to_word(), ); - cb.keccak_table_lookup(create.input_rlc(cb), create.input_length(), output_rlc); - cb.account_write( - call_callee_address.expr(), + cb.account_write_word( + call_callee_address.to_word(), AccountFieldTag::Nonce, - 1.expr(), - 0.expr(), + Word::one(), + Word::zero(), Some(&mut reversion_info), ); for (field_tag, value) in [ - (CallContextFieldTag::Depth, 1.expr()), - (CallContextFieldTag::CallerAddress, tx_caller_address.expr()), + (CallContextFieldTag::Depth, Word::one()), + ( + CallContextFieldTag::CallerAddress, + tx_caller_address.to_word(), + ), ( CallContextFieldTag::CalleeAddress, - call_callee_address.expr(), + call_callee_address.to_word(), ), - (CallContextFieldTag::CallDataOffset, 0.expr()), + (CallContextFieldTag::CallDataOffset, Word::zero()), ( CallContextFieldTag::CallDataLength, - tx_call_data_length.expr(), + Word::from_lo_unchecked(tx_call_data_length.expr()), ), - (CallContextFieldTag::Value, tx_value.expr()), - (CallContextFieldTag::IsStatic, 0.expr()), - (CallContextFieldTag::LastCalleeId, 0.expr()), - (CallContextFieldTag::LastCalleeReturnDataOffset, 0.expr()), - (CallContextFieldTag::LastCalleeReturnDataLength, 0.expr()), - (CallContextFieldTag::IsRoot, 1.expr()), - (CallContextFieldTag::IsCreate, 1.expr()), + (CallContextFieldTag::Value, tx_value.to_word()), + (CallContextFieldTag::IsStatic, Word::zero()), + (CallContextFieldTag::LastCalleeId, Word::zero()), + ( + CallContextFieldTag::LastCalleeReturnDataOffset, + Word::zero(), + ), + ( + CallContextFieldTag::LastCalleeReturnDataLength, + Word::zero(), + ), + (CallContextFieldTag::IsRoot, Word::one()), + (CallContextFieldTag::IsCreate, Word::one()), ( CallContextFieldTag::CodeHash, - cb.curr.state.code_hash.expr(), + cb.curr.state.code_hash.to_word(), ), ] { - cb.call_context_lookup(true.expr(), Some(call_id.expr()), field_tag, value); + cb.call_context_lookup_write(Some(call_id.expr()), field_tag, value); } cb.require_step_state_transition(StepStateTransition { @@ -317,7 +341,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(cb.curr.state.code_hash.expr()), + code_hash: To(cb.curr.state.code_hash.to_word()), gas_left: To(gas_left.clone()), // There are a + 1 reversible writes: // - a TransferWithGasFeeGadget @@ -370,24 +394,39 @@ impl ExecutionGadget for BeginTxGadget { |cb| { // Setup first call's context. for (field_tag, value) in [ - (CallContextFieldTag::Depth, 1.expr()), - (CallContextFieldTag::CallerAddress, tx_caller_address.expr()), - (CallContextFieldTag::CalleeAddress, tx_callee_address.expr()), - (CallContextFieldTag::CallDataOffset, 0.expr()), + (CallContextFieldTag::Depth, Word::one()), + ( + CallContextFieldTag::CallerAddress, + tx_caller_address.to_word(), + ), + ( + CallContextFieldTag::CalleeAddress, + tx_callee_address.to_word(), + ), + (CallContextFieldTag::CallDataOffset, Word::zero()), ( CallContextFieldTag::CallDataLength, - tx_call_data_length.expr(), + Word::from_lo_unchecked(tx_call_data_length.expr()), ), - (CallContextFieldTag::Value, tx_value.expr()), - (CallContextFieldTag::IsStatic, 0.expr()), - (CallContextFieldTag::LastCalleeId, 0.expr()), - (CallContextFieldTag::LastCalleeReturnDataOffset, 0.expr()), - (CallContextFieldTag::LastCalleeReturnDataLength, 0.expr()), - (CallContextFieldTag::IsRoot, 1.expr()), - (CallContextFieldTag::IsCreate, tx_is_create.expr()), - (CallContextFieldTag::CodeHash, phase2_code_hash.expr()), + (CallContextFieldTag::Value, tx_value.to_word()), + (CallContextFieldTag::IsStatic, Word::zero()), + (CallContextFieldTag::LastCalleeId, Word::zero()), + ( + CallContextFieldTag::LastCalleeReturnDataOffset, + Word::zero(), + ), + ( + CallContextFieldTag::LastCalleeReturnDataLength, + Word::zero(), + ), + (CallContextFieldTag::IsRoot, Word::one()), + ( + CallContextFieldTag::IsCreate, + Word::from_lo_unchecked(tx_is_create.expr()), + ), + (CallContextFieldTag::CodeHash, code_hash.to_word()), ] { - cb.call_context_lookup(true.expr(), Some(call_id.expr()), field_tag, value); + cb.call_context_lookup_write(Some(call_id.expr()), field_tag, value); } cb.require_step_state_transition(StepStateTransition { @@ -419,7 +458,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(phase2_code_hash.expr()), + code_hash: To(code_hash.to_word()), gas_left: To(gas_left), reversible_write_counter: To(transfer_with_gas_fee.reversible_w_delta()), log_id: To(0.expr()), @@ -432,21 +471,21 @@ impl ExecutionGadget for BeginTxGadget { tx_id, tx_nonce, tx_gas, - tx_gas_price: tx_gas_price.into(), + tx_gas_price, mul_gas_fee_by_gas, tx_caller_address, tx_caller_address_is_zero, tx_callee_address, call_callee_address, tx_is_create, - tx_value: tx_value.into(), + tx_value, tx_call_data_length, tx_call_data_gas_cost, tx_call_data_word_length, reversion_info, sufficient_gas_left, transfer_with_gas_fee, - phase2_code_hash, + code_hash, is_empty_code_hash, caller_nonce_hash_bytes, create, @@ -498,40 +537,31 @@ impl ExecutionGadget for BeginTxGadget { self.tx_gas .assign(region, offset, Value::known(F::from(tx.gas)))?; self.tx_gas_price - .assign(region, offset, Some(tx.gas_price.to_le_bytes()))?; + .assign_u256(region, offset, tx.gas_price)?; self.mul_gas_fee_by_gas .assign(region, offset, tx.gas_price, tx.gas, gas_fee)?; - let caller_address = tx - .caller_address - .to_scalar() - .expect("unexpected Address -> Scalar conversion failure"); - let callee_address = tx - .callee_address - .to_scalar() - .expect("unexpected Address -> Scalar conversion failure"); self.tx_caller_address - .assign(region, offset, Value::known(caller_address))?; - self.tx_caller_address_is_zero - .assign(region, offset, caller_address)?; + .assign_h160(region, offset, tx.caller_address)?; + self.tx_caller_address_is_zero.assign_u256( + region, + offset, + U256::from_big_endian(&tx.caller_address.to_fixed_bytes()), + )?; self.tx_callee_address - .assign(region, offset, Value::known(callee_address))?; - self.call_callee_address.assign( + .assign_h160(region, offset, tx.callee_address)?; + self.call_callee_address.assign_h160( region, offset, - Value::known( - if tx.is_create { - get_contract_address(tx.caller_address, tx.nonce) - } else { - tx.callee_address - } - .to_scalar() - .expect("unexpected Address -> Scalar conversion failure"), - ), + if tx.is_create { + get_contract_address(tx.caller_address, tx.nonce) + } else { + tx.callee_address + }, )?; self.is_caller_callee_equal.assign( region, offset, - Value::known(F::from((caller_address == callee_address) as u64)), + Value::known(F::from((tx.caller_address == tx.callee_address) as u64)), )?; self.tx_is_create .assign(region, offset, Value::known(F::from(tx.is_create as u64)))?; @@ -564,16 +594,16 @@ impl ExecutionGadget for BeginTxGadget { tx.value, gas_fee, )?; - self.phase2_code_hash - .assign(region, offset, region.word_rlc(callee_code_hash))?; - self.is_empty_code_hash.assign_value( + self.code_hash + .assign_u256(region, offset, callee_code_hash)?; + self.is_empty_code_hash.assign_u256( region, offset, - region.word_rlc(callee_code_hash), - region.empty_code_hash_rlc(), + callee_code_hash, + CodeDB::empty_code_hash().to_word(), )?; self.callee_not_exists - .assign_value(region, offset, region.word_rlc(callee_code_hash))?; + .assign_u256(region, offset, callee_code_hash)?; let untrimmed_contract_addr = { let mut stream = ethers_core::utils::rlp::RlpStream::new(); @@ -581,16 +611,13 @@ impl ExecutionGadget for BeginTxGadget { stream.append(&tx.caller_address); stream.append(ð_types::U256::from(tx.nonce)); let rlp_encoding = stream.out().to_vec(); - keccak256(&rlp_encoding) + keccak256(rlp_encoding) }; - for (c, v) in self - .caller_nonce_hash_bytes - .iter() - .rev() - .zip(untrimmed_contract_addr.iter()) - { - c.assign(region, offset, Value::known(F::from(*v as u64)))?; - } + self.caller_nonce_hash_bytes.assign_u256( + region, + offset, + U256::from_big_endian(&untrimmed_contract_addr), + )?; self.create.assign( region, offset, @@ -600,17 +627,8 @@ impl ExecutionGadget for BeginTxGadget { None, )?; - self.coinbase.assign( - region, - offset, - Value::known( - block - .context - .coinbase - .to_scalar() - .expect("unexpected Address -> Scalar conversion failure"), - ), - )?; + self.coinbase + .assign_h160(region, offset, block.context.coinbase)?; self.is_coinbase_warm.assign( region, offset, diff --git a/zkevm-circuits/src/evm_circuit/execution/bitwise.rs b/zkevm-circuits/src/evm_circuit/execution/bitwise.rs index eef97570fb..9c4fb7d4a3 100644 --- a/zkevm-circuits/src/evm_circuit/execution/bitwise.rs +++ b/zkevm-circuits/src/evm_circuit/execution/bitwise.rs @@ -6,21 +6,24 @@ use crate::{ util::{ common_gadget::SameContextGadget, constraint_builder::{EVMConstraintBuilder, StepStateTransition, Transition::Delta}, - CachedRegion, Word, + CachedRegion, }, witness::{Block, Call, ExecStep, Transaction}, }, - util::Expr, + util::{ + word::{Word32Cell, WordExpr}, + Expr, + }, }; -use eth_types::{evm_types::OpcodeId, Field, ToLittleEndian}; +use eth_types::{evm_types::OpcodeId, Field}; use halo2_proofs::plonk::Error; #[derive(Clone, Debug)] pub(crate) struct BitwiseGadget { same_context: SameContextGadget, - a: Word, - b: Word, - c: Word, + a: Word32Cell, + b: Word32Cell, + c: Word32Cell, } impl ExecutionGadget for BitwiseGadget { @@ -31,13 +34,13 @@ impl ExecutionGadget for BitwiseGadget { fn configure(cb: &mut EVMConstraintBuilder) -> Self { let opcode = cb.query_cell(); - let a = cb.query_word_rlc(); - let b = cb.query_word_rlc(); - let c = cb.query_word_rlc(); + let a = cb.query_word32(); + let b = cb.query_word32(); + let c = cb.query_word32(); - cb.stack_pop(a.expr()); - cb.stack_pop(b.expr()); - cb.stack_push(c.expr()); + cb.stack_pop_word(a.to_word()); + cb.stack_pop_word(b.to_word()); + cb.stack_push_word(c.to_word()); // Because opcode AND, OR, and XOR are continuous, so we can make the // FixedTableTag of them also continuous, and use the opcode delta from @@ -50,9 +53,9 @@ impl ExecutionGadget for BitwiseGadget { Lookup::Fixed { tag: tag.clone(), values: [ - a.cells[idx].expr(), - b.cells[idx].expr(), - c.cells[idx].expr(), + a.limbs[idx].expr(), + b.limbs[idx].expr(), + c.limbs[idx].expr(), ], }, ); @@ -88,9 +91,9 @@ impl ExecutionGadget for BitwiseGadget { self.same_context.assign_exec_step(region, offset, step)?; let [a, b, c] = [0, 1, 2].map(|index| block.get_rws(step, index).stack_value()); - self.a.assign(region, offset, Some(a.to_le_bytes()))?; - self.b.assign(region, offset, Some(b.to_le_bytes()))?; - self.c.assign(region, offset, Some(c.to_le_bytes()))?; + self.a.assign_u256(region, offset, a)?; + self.b.assign_u256(region, offset, b)?; + self.c.assign_u256(region, offset, c)?; Ok(()) } diff --git a/zkevm-circuits/src/evm_circuit/execution/block_ctx.rs b/zkevm-circuits/src/evm_circuit/execution/block_ctx.rs index f53b0c96b1..10e5bbc24d 100644 --- a/zkevm-circuits/src/evm_circuit/execution/block_ctx.rs +++ b/zkevm-circuits/src/evm_circuit/execution/block_ctx.rs @@ -1,34 +1,40 @@ use crate::{ evm_circuit::{ - execution::ExecutionGadget, - param::{N_BYTES_ACCOUNT_ADDRESS, N_BYTES_U64, N_BYTES_WORD}, step::ExecutionState, util::{ common_gadget::SameContextGadget, constraint_builder::{EVMConstraintBuilder, StepStateTransition, Transition::Delta}, - from_bytes, CachedRegion, RandomLinearCombination, + CachedRegion, }, witness::{Block, Call, ExecStep, Transaction}, }, table::BlockContextFieldTag, - util::Expr, + util::{ + word::{WordCell, WordExpr}, + Expr, + }, }; use bus_mapping::evm::OpcodeId; -use eth_types::{Field, ToLittleEndian}; +use eth_types::Field; use halo2_proofs::plonk::Error; +use super::ExecutionGadget; + #[derive(Clone, Debug)] -pub(crate) struct BlockCtxGadget { +pub(crate) struct BlockCtxGadget { same_context: SameContextGadget, - value: RandomLinearCombination, + value: WordCell, } -impl BlockCtxGadget { - fn construct(cb: &mut EVMConstraintBuilder) -> Self { - let value = cb.query_word_rlc(); +impl ExecutionGadget for BlockCtxGadget { + const NAME: &'static str = "BlockCTX"; + + const EXECUTION_STATE: ExecutionState = ExecutionState::BLOCKCTX; + + fn configure(cb: &mut EVMConstraintBuilder) -> Self { + let value = cb.query_word_unchecked(); // block table lookup below - // Push the const generic parameter N_BYTES value to the stack - cb.stack_push(value.expr()); + cb.stack_push_word(value.to_word()); // Get op's FieldTag let opcode = cb.query_cell(); @@ -37,12 +43,7 @@ impl BlockCtxGadget { // Lookup block table with block context ops // TIMESTAMP/NUMBER/GASLIMIT, COINBASE and DIFFICULTY/BASEFEE - let value_expr = if N_BYTES == N_BYTES_WORD { - value.expr() - } else { - from_bytes::expr(&value.cells) - }; - cb.block_lookup(blockctx_tag, None, value_expr); + cb.block_lookup_word(blockctx_tag, None, value.to_word()); // State transition let step_state_transition = StepStateTransition { @@ -59,109 +60,6 @@ impl BlockCtxGadget { value, } } -} - -#[derive(Clone, Debug)] -pub(crate) struct BlockCtxU64Gadget { - value_u64: BlockCtxGadget, -} - -impl ExecutionGadget for BlockCtxU64Gadget { - const NAME: &'static str = "BlockCTXU64"; - - const EXECUTION_STATE: ExecutionState = ExecutionState::BLOCKCTXU64; - - fn configure(cb: &mut EVMConstraintBuilder) -> Self { - let value_u64 = BlockCtxGadget::construct(cb); - - Self { value_u64 } - } - - fn assign_exec_step( - &self, - region: &mut CachedRegion<'_, '_, F>, - offset: usize, - block: &Block, - _: &Transaction, - _: &Call, - step: &ExecStep, - ) -> Result<(), Error> { - self.value_u64 - .same_context - .assign_exec_step(region, offset, step)?; - - let value = block.get_rws(step, 0).stack_value(); - - self.value_u64.value.assign( - region, - offset, - Some(u64::try_from(value).unwrap().to_le_bytes()), - )?; - - Ok(()) - } -} - -#[derive(Clone, Debug)] -pub(crate) struct BlockCtxU160Gadget { - value_u160: BlockCtxGadget, -} - -impl ExecutionGadget for BlockCtxU160Gadget { - const NAME: &'static str = "BlockCTXU160"; - - const EXECUTION_STATE: ExecutionState = ExecutionState::BLOCKCTXU160; - - fn configure(cb: &mut EVMConstraintBuilder) -> Self { - let value_u160 = BlockCtxGadget::construct(cb); - - Self { value_u160 } - } - - fn assign_exec_step( - &self, - region: &mut CachedRegion<'_, '_, F>, - offset: usize, - block: &Block, - _: &Transaction, - _: &Call, - step: &ExecStep, - ) -> Result<(), Error> { - self.value_u160 - .same_context - .assign_exec_step(region, offset, step)?; - - let value = block.get_rws(step, 0).stack_value(); - - self.value_u160.value.assign( - region, - offset, - Some( - value.to_le_bytes()[..N_BYTES_ACCOUNT_ADDRESS] - .try_into() - .unwrap(), - ), - )?; - - Ok(()) - } -} - -#[derive(Clone, Debug)] -pub(crate) struct BlockCtxU256Gadget { - value_u256: BlockCtxGadget, -} - -impl ExecutionGadget for BlockCtxU256Gadget { - const NAME: &'static str = "BLOCKCTXU256"; - - const EXECUTION_STATE: ExecutionState = ExecutionState::BLOCKCTXU256; - - fn configure(cb: &mut EVMConstraintBuilder) -> Self { - let value_u256 = BlockCtxGadget::construct(cb); - - Self { value_u256 } - } fn assign_exec_step( &self, @@ -172,15 +70,11 @@ impl ExecutionGadget for BlockCtxU256Gadget { _: &Call, step: &ExecStep, ) -> Result<(), Error> { - self.value_u256 - .same_context - .assign_exec_step(region, offset, step)?; + self.same_context.assign_exec_step(region, offset, step)?; let value = block.get_rws(step, 0).stack_value(); - self.value_u256 - .value - .assign(region, offset, Some(value.to_le_bytes()))?; + self.value.assign_u256(region, offset, value)?; Ok(()) } diff --git a/zkevm-circuits/src/evm_circuit/execution/blockhash.rs b/zkevm-circuits/src/evm_circuit/execution/blockhash.rs index a811c09af9..6b8df8f453 100644 --- a/zkevm-circuits/src/evm_circuit/execution/blockhash.rs +++ b/zkevm-circuits/src/evm_circuit/execution/blockhash.rs @@ -16,9 +16,10 @@ use crate::{ witness::{Block, Call, ExecStep, Transaction}, }, table::BlockContextFieldTag, + util::word::WordExpr, }; use bus_mapping::evm::OpcodeId; -use eth_types::{Field, ToLittleEndian, ToScalar}; +use eth_types::{Field, ToScalar}; use gadgets::util::{not, Expr}; use halo2_proofs::{circuit::Value, plonk::Error}; @@ -27,7 +28,7 @@ pub(crate) struct BlockHashGadget { same_context: SameContextGadget, block_number: WordByteCapGadget, current_block_number: Cell, - block_hash: Word, + block_hash: Word>, diff_lt: LtGadget, } @@ -38,16 +39,16 @@ impl ExecutionGadget for BlockHashGadget { fn configure(cb: &mut EVMConstraintBuilder) -> Self { let current_block_number = cb.query_cell(); - cb.block_lookup( + cb.block_lookup_word( BlockContextFieldTag::Number.expr(), None, - current_block_number.expr(), + Word::from_lo_unchecked(current_block_number.expr()), ); let block_number = WordByteCapGadget::construct(cb, current_block_number.expr()); - cb.stack_pop(block_number.original_word()); + cb.stack_pop_word(block_number.original_word_new().to_word()); - let block_hash = cb.query_word_rlc(); + let block_hash = cb.query_word_unchecked(); let diff_lt = LtGadget::construct( cb, @@ -58,21 +59,21 @@ impl ExecutionGadget for BlockHashGadget { let is_valid = and::expr([block_number.lt_cap(), diff_lt.expr()]); cb.condition(is_valid.expr(), |cb| { - cb.block_lookup( + cb.block_lookup_word( BlockContextFieldTag::BlockHash.expr(), Some(block_number.valid_value()), - block_hash.expr(), + block_hash.to_word(), ); }); cb.condition(not::expr(is_valid), |cb| { - cb.require_zero( + cb.require_zero_word( "Invalid block number for block hash lookup", - block_hash.expr(), + block_hash.to_word(), ); }); - cb.stack_push(block_hash.expr()); + cb.stack_push_word(block_hash.to_word()); let step_state_transition = StepStateTransition { rw_counter: Delta(2.expr()), @@ -115,11 +116,8 @@ impl ExecutionGadget for BlockHashGadget { self.current_block_number .assign(region, offset, Value::known(current_block_number))?; - self.block_hash.assign( - region, - offset, - Some(block.get_rws(step, 1).stack_value().to_le_bytes()), - )?; + self.block_hash + .assign_u256(region, offset, block.get_rws(step, 1).stack_value())?; self.diff_lt.assign( region, diff --git a/zkevm-circuits/src/evm_circuit/execution/byte.rs b/zkevm-circuits/src/evm_circuit/execution/byte.rs index a21c0570e8..65719416e9 100644 --- a/zkevm-circuits/src/evm_circuit/execution/byte.rs +++ b/zkevm-circuits/src/evm_circuit/execution/byte.rs @@ -6,11 +6,14 @@ use crate::{ common_gadget::SameContextGadget, constraint_builder::{EVMConstraintBuilder, StepStateTransition, Transition::Delta}, math_gadget::{IsEqualGadget, IsZeroGadget}, - sum, CachedRegion, Word, + sum, CachedRegion, }, witness::{Block, Call, ExecStep, Transaction}, }, - util::Expr, + util::{ + word::{Word, Word32Cell, WordExpr}, + Expr, + }, }; use array_init::array_init; use bus_mapping::evm::OpcodeId; @@ -20,8 +23,8 @@ use halo2_proofs::plonk::Error; #[derive(Clone, Debug)] pub(crate) struct ByteGadget { same_context: SameContextGadget, - index: Word, - value: Word, + index: Word32Cell, + value: Word32Cell, is_msb_sum_zero: IsZeroGadget, is_byte_selected: [IsEqualGadget; 32], } @@ -32,14 +35,14 @@ impl ExecutionGadget for ByteGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::BYTE; fn configure(cb: &mut EVMConstraintBuilder) -> Self { - let index = cb.query_word_rlc(); - let value = cb.query_word_rlc(); + let index = cb.query_word32(); + let value = cb.query_word32(); // 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 // values here and then check if it's non-zero so we can use // that as an additional condition when to copy the byte value. - let is_msb_sum_zero = IsZeroGadget::construct(cb, sum::expr(&index.cells[1..32])); + let is_msb_sum_zero = IsZeroGadget::construct(cb, sum::expr(&index.limbs[1..32])); // Now we just need to check that `result[0]` is the sum of all copied // bytes. We go byte by byte and check if `idx == index[0]`. @@ -50,11 +53,11 @@ impl ExecutionGadget for ByteGadget { let is_byte_selected = array_init(|idx| { // Check if this byte is selected looking only at the LSB of the // index word - IsEqualGadget::construct(cb, index.cells[0].expr(), (31 - idx).expr()) + IsEqualGadget::construct(cb, index.limbs[0].expr(), (31 - idx).expr()) }); // Sum all possible selected bytes - let selected_byte = value.cells.iter().zip(is_byte_selected.iter()).fold( + let selected_byte = value.limbs.iter().zip(is_byte_selected.iter()).fold( 0.expr(), |acc, (cell, is_selected)| { acc + is_selected.expr() * is_msb_sum_zero.expr() * cell.expr() @@ -65,9 +68,9 @@ impl ExecutionGadget for ByteGadget { // push the selected byte on the stack // We can push the selected byte here directly because // it only uses the LSB of a word. - cb.stack_pop(index.expr()); - cb.stack_pop(value.expr()); - cb.stack_push(selected_byte); + cb.stack_pop_word(index.to_word()); + cb.stack_pop_word(value.to_word()); + cb.stack_push_word(Word::from_lo_unchecked(selected_byte)); // State transition let step_state_transition = StepStateTransition { @@ -101,21 +104,22 @@ impl ExecutionGadget for ByteGadget { self.same_context.assign_exec_step(region, offset, step)?; // Inputs/Outputs - let index = block.get_rws(step, 0).stack_value().to_le_bytes(); - let value = block.get_rws(step, 1).stack_value().to_le_bytes(); - self.index.assign(region, offset, Some(index))?; - self.value.assign(region, offset, Some(value))?; + let index = block.get_rws(step, 0).stack_value(); + let value = block.get_rws(step, 1).stack_value(); + let index_bytes = index.to_le_bytes(); + self.index.assign_u256(region, offset, index)?; + self.value.assign_u256(region, offset, value)?; // Set `is_msb_sum_zero` self.is_msb_sum_zero - .assign(region, offset, sum::value(&index[1..32]))?; + .assign(region, offset, sum::value(&index_bytes[1..32]))?; // Set `is_byte_selected` for i in 0..32 { self.is_byte_selected[i].assign( region, offset, - F::from(index[0] as u64), + F::from(index_bytes[0] as u64), F::from((31 - i) as u64), )?; } diff --git a/zkevm-circuits/src/evm_circuit/execution/calldatacopy.rs b/zkevm-circuits/src/evm_circuit/execution/calldatacopy.rs index 6d1fb475cc..38cea8758c 100644 --- a/zkevm-circuits/src/evm_circuit/execution/calldatacopy.rs +++ b/zkevm-circuits/src/evm_circuit/execution/calldatacopy.rs @@ -15,7 +15,10 @@ use crate::{ witness::{Block, Call, ExecStep, Transaction}, }, table::CallContextFieldTag, - util::Expr, + util::{ + word::{Word, WordExpr}, + Expr, + }, }; use bus_mapping::{circuit_input_builder::CopyDataType, evm::OpcodeId}; use eth_types::{evm_types::GasCost, Field, ToScalar}; @@ -48,24 +51,27 @@ impl ExecutionGadget for CallDataCopyGadget { let call_data_length = cb.query_cell(); let call_data_offset = cb.query_cell(); - let length = cb.query_word_rlc(); - let memory_offset = cb.query_cell_phase2(); + let length = cb.query_memory_address(); + let memory_offset = cb.query_word_unchecked(); let data_offset = WordByteCapGadget::construct(cb, call_data_length.expr()); // Pop memory_offset, data_offset, length from stack - cb.stack_pop(memory_offset.expr()); - cb.stack_pop(data_offset.original_word()); - cb.stack_pop(length.expr()); + cb.stack_pop_word(memory_offset.to_word()); + cb.stack_pop_word(data_offset.original_word_new().to_word()); + cb.stack_pop_word(length.to_word()); // Lookup the calldata_length and caller_address in Tx context table or // Call context table cb.condition(cb.curr.state.is_root.expr(), |cb| { - cb.call_context_lookup(false.expr(), None, CallContextFieldTag::TxId, src_id.expr()); - cb.call_context_lookup( - false.expr(), + cb.call_context_lookup_read( + None, + CallContextFieldTag::TxId, + Word::from_lo_unchecked(src_id.expr()), + ); + cb.call_context_lookup_read( None, CallContextFieldTag::CallDataLength, - call_data_length.expr(), + Word::from_lo_unchecked(call_data_length.expr()), ); cb.require_zero( "call_data_offset == 0 in the root call", @@ -73,23 +79,20 @@ impl ExecutionGadget for CallDataCopyGadget { ); }); cb.condition(1.expr() - cb.curr.state.is_root.expr(), |cb| { - cb.call_context_lookup( - false.expr(), + cb.call_context_lookup_read( None, CallContextFieldTag::CallerId, - src_id.expr(), + Word::from_lo_unchecked(src_id.expr()), ); - cb.call_context_lookup( - false.expr(), + cb.call_context_lookup_read( None, CallContextFieldTag::CallDataLength, - call_data_length.expr(), + Word::from_lo_unchecked(call_data_length.expr()), ); - cb.call_context_lookup( - false.expr(), + cb.call_context_lookup_read( None, CallContextFieldTag::CallDataOffset, - call_data_offset.expr(), + Word::from_lo_unchecked(call_data_offset.expr()), ); }); @@ -121,9 +124,9 @@ impl ExecutionGadget for CallDataCopyGadget { let src_addr_end = call_data_offset.expr() + call_data_length.expr(); cb.copy_table_lookup( - src_id.expr(), + Word::from_lo_unchecked(src_id.expr()), src_tag, - cb.curr.state.call_id.expr(), + Word::from_lo_unchecked(cb.curr.state.call_id.expr()), CopyDataType::Memory.expr(), src_addr, src_addr_end, diff --git a/zkevm-circuits/src/evm_circuit/execution/calldataload.rs b/zkevm-circuits/src/evm_circuit/execution/calldataload.rs index 555a105667..3252b97adb 100644 --- a/zkevm-circuits/src/evm_circuit/execution/calldataload.rs +++ b/zkevm-circuits/src/evm_circuit/execution/calldataload.rs @@ -22,7 +22,10 @@ use crate::{ witness::{Block, Call, ExecStep, Transaction}, }, table::{CallContextFieldTag, TxContextFieldTag}, - util::Expr, + util::{ + word::{Word, Word32, WordExpr}, + Expr, + }, }; use super::ExecutionGadget; @@ -65,22 +68,20 @@ impl ExecutionGadget for CallDataLoadGadget { let call_data_offset = cb.query_cell(); let data_offset = WordByteCapGadget::construct(cb, call_data_length.expr()); - cb.stack_pop(data_offset.original_word()); + cb.stack_pop_word(data_offset.original_word_new().to_word()); cb.condition( and::expr([data_offset.not_overflow(), cb.curr.state.is_root.expr()]), |cb| { - cb.call_context_lookup( - false.expr(), + cb.call_context_lookup_read( None, CallContextFieldTag::TxId, - src_id.expr(), + Word::from_lo_unchecked(src_id.expr()), ); - cb.call_context_lookup( - false.expr(), + cb.call_context_lookup_read( None, CallContextFieldTag::CallDataLength, - call_data_length.expr(), + Word::from_lo_unchecked(call_data_length.expr()), ); cb.require_equal( "if is_root then call_data_offset == 0", @@ -96,23 +97,20 @@ impl ExecutionGadget for CallDataLoadGadget { not::expr(cb.curr.state.is_root.expr()), ]), |cb| { - cb.call_context_lookup( - false.expr(), + cb.call_context_lookup_read( None, CallContextFieldTag::CallerId, - src_id.expr(), + Word::from_lo_unchecked(src_id.expr()), ); - cb.call_context_lookup( - false.expr(), + cb.call_context_lookup_read( None, CallContextFieldTag::CallDataLength, - call_data_length.expr(), + Word::from_lo_unchecked(call_data_length.expr()), ); - cb.call_context_lookup( - false.expr(), + cb.call_context_lookup_read( None, CallContextFieldTag::CallDataOffset, - call_data_offset.expr(), + Word::from_lo_unchecked(call_data_offset.expr()), ); }, ); @@ -139,11 +137,11 @@ impl ExecutionGadget for CallDataLoadGadget { cb.curr.state.is_root.expr(), ]), |cb| { - cb.tx_context_lookup( + cb.tx_context_lookup_word( src_id.expr(), TxContextFieldTag::CallData, Some(src_addr.expr() + idx.expr()), - buffer_reader.byte(idx), + Word::from_lo_unchecked(buffer_reader.byte(idx)), ); }, ); @@ -174,13 +172,13 @@ 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(); - let calldata_word = cb.word_rlc(calldata_word); - cb.require_zero( + let calldata_word = Word32::new(calldata_word); + cb.require_zero_word( "Stack push result must be 0 if stack pop offset is Uint64 overflow", - data_offset.overflow() * calldata_word.expr(), + calldata_word.to_word().mul_selector(data_offset.overflow()), ); - cb.stack_push(calldata_word); + cb.stack_push_word(calldata_word.to_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 dc6028e53b..1864d337d5 100644 --- a/zkevm-circuits/src/evm_circuit/execution/calldatasize.rs +++ b/zkevm-circuits/src/evm_circuit/execution/calldatasize.rs @@ -1,26 +1,28 @@ use crate::{ evm_circuit::{ execution::ExecutionGadget, - param::N_BYTES_CALLDATASIZE, step::ExecutionState, util::{ common_gadget::SameContextGadget, constraint_builder::{EVMConstraintBuilder, StepStateTransition, Transition::Delta}, - from_bytes, CachedRegion, RandomLinearCombination, + CachedRegion, }, witness::{Block, Call, ExecStep, Transaction}, }, table::CallContextFieldTag, - util::Expr, + util::{ + word::{WordCell, WordExpr}, + Expr, + }, }; use bus_mapping::evm::OpcodeId; -use eth_types::{Field, ToLittleEndian}; +use eth_types::Field; use halo2_proofs::plonk::Error; #[derive(Clone, Debug)] pub(crate) struct CallDataSizeGadget { same_context: SameContextGadget, - call_data_size: RandomLinearCombination, + call_data_size: WordCell, } impl ExecutionGadget for CallDataSizeGadget { @@ -32,16 +34,15 @@ 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_word_rlc(); - cb.call_context_lookup( - false.expr(), + let call_data_size = cb.query_word_unchecked(); + cb.call_context_lookup_read( None, CallContextFieldTag::CallDataLength, - from_bytes::expr(&call_data_size.cells), + call_data_size.to_word(), ); // The calldatasize should be pushed to the top of the stack. - cb.stack_push(call_data_size.expr()); + cb.stack_push_word(call_data_size.to_word()); let step_state_transition = StepStateTransition { rw_counter: Delta(2.expr()), @@ -72,15 +73,8 @@ impl ExecutionGadget for CallDataSizeGadget { let call_data_size = block.get_rws(step, 1).stack_value(); - self.call_data_size.assign( - region, - offset, - Some( - call_data_size.to_le_bytes()[..N_BYTES_CALLDATASIZE] - .try_into() - .unwrap(), - ), - )?; + self.call_data_size + .assign_u64(region, offset, call_data_size.as_u64())?; Ok(()) } diff --git a/zkevm-circuits/src/evm_circuit/execution/caller.rs b/zkevm-circuits/src/evm_circuit/execution/caller.rs index a57b97dc8e..5dcedd8ab0 100644 --- a/zkevm-circuits/src/evm_circuit/execution/caller.rs +++ b/zkevm-circuits/src/evm_circuit/execution/caller.rs @@ -1,27 +1,28 @@ use crate::{ evm_circuit::{ execution::ExecutionGadget, - param::N_BYTES_ACCOUNT_ADDRESS, step::ExecutionState, util::{ common_gadget::SameContextGadget, constraint_builder::{EVMConstraintBuilder, StepStateTransition, Transition::Delta}, - from_bytes, CachedRegion, RandomLinearCombination, + CachedRegion, }, witness::{Block, Call, ExecStep, Transaction}, }, table::CallContextFieldTag, - util::Expr, + util::{ + word::{WordCell, WordExpr}, + Expr, + }, }; use bus_mapping::evm::OpcodeId; -use eth_types::{Field, ToLittleEndian}; +use eth_types::Field; use halo2_proofs::plonk::Error; #[derive(Clone, Debug)] pub(crate) struct CallerGadget { same_context: SameContextGadget, - // Using RLC to match against rw_table->stack_op value - caller_address: RandomLinearCombination, + caller_address: WordCell, } impl ExecutionGadget for CallerGadget { @@ -30,18 +31,17 @@ impl ExecutionGadget for CallerGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::CALLER; fn configure(cb: &mut EVMConstraintBuilder) -> Self { - let caller_address = cb.query_word_rlc(); + let caller_address = cb.query_word_unchecked(); // Lookup rw_table -> call_context with caller address - cb.call_context_lookup( - false.expr(), + cb.call_context_lookup_read( None, // cb.curr.state.call_id CallContextFieldTag::CallerAddress, - from_bytes::expr(&caller_address.cells), + caller_address.to_word(), ); // Push the value to the stack - cb.stack_push(caller_address.expr()); + cb.stack_push_word(caller_address.to_word()); // State transition let opcode = cb.query_cell(); @@ -73,15 +73,7 @@ impl ExecutionGadget for CallerGadget { let caller = block.get_rws(step, 1).stack_value(); - self.caller_address.assign( - region, - offset, - Some( - caller.to_le_bytes()[..N_BYTES_ACCOUNT_ADDRESS] - .try_into() - .unwrap(), - ), - )?; + self.caller_address.assign_u256(region, offset, caller)?; Ok(()) } diff --git a/zkevm-circuits/src/evm_circuit/execution/callop.rs b/zkevm-circuits/src/evm_circuit/execution/callop.rs index 3f13f31e48..0233c052c0 100644 --- a/zkevm-circuits/src/evm_circuit/execution/callop.rs +++ b/zkevm-circuits/src/evm_circuit/execution/callop.rs @@ -1,17 +1,22 @@ -use crate::evm_circuit::{ - execution::ExecutionGadget, - param::{N_BYTES_GAS, N_BYTES_U64}, - step::ExecutionState, - util::{ - and, - common_gadget::{CommonCallGadget, TransferGadget}, - constraint_builder::{ - ConstrainBuilderCommon, EVMConstraintBuilder, ReversionInfo, StepStateTransition, - Transition::{Delta, To}, +use crate::{ + evm_circuit::{ + execution::ExecutionGadget, + param::{N_BYTES_GAS, N_BYTES_U64}, + step::ExecutionState, + util::{ + and, + common_gadget::{CommonCallGadget, TransferGadget}, + constraint_builder::{ + ConstrainBuilderCommon, EVMConstraintBuilder, ReversionInfo, StepStateTransition, + Transition::{Delta, To}, + }, + math_gadget::{ + ConstantDivisionGadget, IsZeroGadget, LtGadget, LtWordGadget, MinMaxGadget, + }, + not, or, select, CachedRegion, Cell, }, - math_gadget::{ConstantDivisionGadget, IsZeroGadget, LtGadget, LtWordGadget, MinMaxGadget}, - not, or, select, CachedRegion, Cell, Word, }, + util::word::{Word, WordCell, WordExpr}, }; use crate::{ @@ -20,7 +25,7 @@ use crate::{ util::Expr, }; use bus_mapping::evm::OpcodeId; -use eth_types::{evm_types::GAS_STIPEND_CALL_WITH_VALUE, Field, ToLittleEndian, ToScalar, U256}; +use eth_types::{evm_types::GAS_STIPEND_CALL_WITH_VALUE, Field, U256}; use halo2_proofs::{circuit::Value, plonk::Error}; /// Gadget for call related opcodes. It supports `OpcodeId::CALL`, @@ -36,18 +41,18 @@ pub(crate) struct CallOpGadget { is_staticcall: IsZeroGadget, tx_id: Cell, reversion_info: ReversionInfo, - current_callee_address: Cell, - current_caller_address: Cell, + current_callee_address: WordCell, + current_caller_address: WordCell, is_static: Cell, depth: Cell, call: CommonCallGadget, - current_value: Word, + current_value: WordCell, is_warm: Cell, is_warm_prev: Cell, callee_reversion_info: ReversionInfo, transfer: TransferGadget, // current handling Call* opcode's caller balance - caller_balance_word: Word, + caller_balance_word: WordCell, // check if insufficient balance case is_insufficient_balance: LtWordGadget, is_depth_ok: LtGadget, @@ -75,17 +80,15 @@ impl ExecutionGadget for CallOpGadget { let tx_id = cb.call_context(None, CallContextFieldTag::TxId); let mut reversion_info = cb.reversion_info_read(None); - let [is_static, depth, current_callee_address] = [ - CallContextFieldTag::IsStatic, - CallContextFieldTag::Depth, - CallContextFieldTag::CalleeAddress, - ] - .map(|field_tag| cb.call_context(None, field_tag)); + let [is_static, depth] = [CallContextFieldTag::IsStatic, CallContextFieldTag::Depth] + .map(|field_tag| cb.call_context(None, field_tag)); + let current_callee_address = + cb.call_context_read_as_word(None, CallContextFieldTag::CalleeAddress); let (current_caller_address, current_value) = cb.condition(is_delegatecall.expr(), |cb| { ( - cb.call_context(None, CallContextFieldTag::CallerAddress), - cb.call_context_read(None, CallContextFieldTag::Value), + cb.call_context_read_as_word(None, CallContextFieldTag::CallerAddress), + cb.call_context_read_as_word(None, CallContextFieldTag::Value), ) }); @@ -97,36 +100,37 @@ impl ExecutionGadget for CallOpGadget { is_staticcall.expr(), ); cb.condition(not::expr(is_call.expr() + is_callcode.expr()), |cb| { - cb.require_zero( + cb.require_zero_word( "for non call/call code, value is zero", - call_gadget.value.expr(), + call_gadget.value.to_word(), ); }); - let caller_address = select::expr( + let caller_address = Word::select( is_delegatecall.expr(), - current_caller_address.expr(), - current_callee_address.expr(), + current_caller_address.to_word(), + current_callee_address.to_word(), ); - let callee_address = select::expr( + let callee_address = Word::select( is_callcode.expr() + is_delegatecall.expr(), - current_callee_address.expr(), - call_gadget.callee_address_expr(), + current_callee_address.to_word(), + call_gadget.callee_address_word(), ); // Add callee to access list let is_warm = cb.query_bool(); let is_warm_prev = cb.query_bool(); - cb.account_access_list_write( + cb.account_access_list_write_unchecked( tx_id.expr(), - call_gadget.callee_address_expr(), + call_gadget.callee_address_word(), is_warm.expr(), is_warm_prev.expr(), Some(&mut reversion_info), ); // Propagate rw_counter_end_of_reversion and is_persistent - let mut callee_reversion_info = cb.reversion_info_write(Some(callee_call_id.expr())); + let mut callee_reversion_info = + cb.reversion_info_write_unchecked(Some(callee_call_id.expr())); cb.require_equal( "callee_is_persistent == is_persistent ⋅ is_success", callee_reversion_info.is_persistent(), @@ -147,14 +151,17 @@ impl ExecutionGadget for CallOpGadget { ); }); - let caller_balance_word = cb.query_word_rlc(); - cb.account_read( - caller_address.expr(), + let caller_balance_word = cb.query_word_unchecked(); + cb.account_read_word( + caller_address.to_word(), AccountFieldTag::Balance, - caller_balance_word.expr(), + caller_balance_word.to_word(), + ); + let is_insufficient_balance = LtWordGadget::construct( + cb, + &caller_balance_word.to_word(), + &call_gadget.value.to_word(), ); - let is_insufficient_balance = - LtWordGadget::construct(cb, &caller_balance_word, &call_gadget.value.clone().into()); // depth < 1025 let is_depth_ok = LtGadget::construct(cb, depth.expr(), 1025.expr()); @@ -180,8 +187,8 @@ impl ExecutionGadget for CallOpGadget { |cb| { TransferGadget::construct( cb, - caller_address.expr(), - callee_address.expr(), + caller_address.to_word(), + callee_address.to_word(), not::expr(call_gadget.callee_not_exists.expr()), 0.expr(), call_gadget.value.clone(), @@ -235,7 +242,7 @@ impl ExecutionGadget for CallOpGadget { CallContextFieldTag::LastCalleeReturnDataOffset, CallContextFieldTag::LastCalleeReturnDataLength, ] { - cb.call_context_lookup(true.expr(), None, field_tag, 0.expr()); + cb.call_context_lookup_write(None, field_tag, Word::zero()); } // For CALL opcode, it has an extra stack pop `value` (+1) and if the value is @@ -280,7 +287,7 @@ impl ExecutionGadget for CallOpGadget { CallContextFieldTag::LastCalleeReturnDataOffset, CallContextFieldTag::LastCalleeReturnDataLength, ] { - cb.call_context_lookup(true.expr(), None, field_tag, 0.expr()); + cb.call_context_lookup_write(None, field_tag, Word::zero()); } cb.require_step_state_transition(StepStateTransition { @@ -323,54 +330,76 @@ impl ExecutionGadget for CallOpGadget { cb.curr.state.reversible_write_counter.expr() + 1.expr(), ), ] { - cb.call_context_lookup(true.expr(), None, field_tag, value); + cb.call_context_lookup_write(None, field_tag, Word::from_lo_unchecked(value)); } // Setup next call's context. let cd_address = call_gadget.cd_address.clone(); let rd_address = call_gadget.rd_address.clone(); for (field_tag, value) in [ - (CallContextFieldTag::CallerId, cb.curr.state.call_id.expr()), - (CallContextFieldTag::TxId, tx_id.expr()), - (CallContextFieldTag::Depth, depth.expr() + 1.expr()), + ( + CallContextFieldTag::CallerId, + Word::from_lo_unchecked(cb.curr.state.call_id.expr()), + ), + ( + CallContextFieldTag::TxId, + Word::from_lo_unchecked(tx_id.expr()), + ), + ( + CallContextFieldTag::Depth, + Word::from_lo_unchecked(depth.expr() + 1.expr()), + ), (CallContextFieldTag::CallerAddress, caller_address), (CallContextFieldTag::CalleeAddress, callee_address), - (CallContextFieldTag::CallDataOffset, cd_address.offset()), - (CallContextFieldTag::CallDataLength, cd_address.length()), - (CallContextFieldTag::ReturnDataOffset, rd_address.offset()), - (CallContextFieldTag::ReturnDataLength, rd_address.length()), + ( + CallContextFieldTag::CallDataOffset, + Word::from_lo_unchecked(cd_address.offset()), + ), + ( + CallContextFieldTag::CallDataLength, + Word::from_lo_unchecked(cd_address.length()), + ), + ( + CallContextFieldTag::ReturnDataOffset, + Word::from_lo_unchecked(rd_address.offset()), + ), + ( + CallContextFieldTag::ReturnDataLength, + Word::from_lo_unchecked(rd_address.length()), + ), ( CallContextFieldTag::Value, - select::expr( + Word::select( is_delegatecall.expr(), - current_value.expr(), - call_gadget.value.expr(), + current_value.to_word(), + call_gadget.value.to_word(), ), ), ( CallContextFieldTag::IsSuccess, - call_gadget.is_success.expr(), + Word::from_lo_unchecked(call_gadget.is_success.expr()), ), ( CallContextFieldTag::IsStatic, - or::expr([is_static.expr(), is_staticcall.expr()]), + Word::from_lo_unchecked(or::expr([is_static.expr(), is_staticcall.expr()])), + ), + (CallContextFieldTag::LastCalleeId, Word::zero()), + ( + CallContextFieldTag::LastCalleeReturnDataOffset, + Word::zero(), + ), + ( + CallContextFieldTag::LastCalleeReturnDataLength, + Word::zero(), ), - (CallContextFieldTag::LastCalleeId, 0.expr()), - (CallContextFieldTag::LastCalleeReturnDataOffset, 0.expr()), - (CallContextFieldTag::LastCalleeReturnDataLength, 0.expr()), - (CallContextFieldTag::IsRoot, 0.expr()), - (CallContextFieldTag::IsCreate, 0.expr()), + (CallContextFieldTag::IsRoot, Word::zero()), + (CallContextFieldTag::IsCreate, Word::zero()), ( CallContextFieldTag::CodeHash, - call_gadget.callee_code_hash.expr(), + call_gadget.callee_code_hash.to_word(), ), ] { - cb.call_context_lookup( - true.expr(), - Some(callee_call_id.expr()), - field_tag, - value, - ); + cb.call_context_lookup_write(Some(callee_call_id.expr()), field_tag, value); } // Give gas stipend if value is not zero @@ -399,7 +428,7 @@ impl ExecutionGadget for CallOpGadget { call_id: To(callee_call_id.expr()), is_root: To(false.expr()), is_create: To(false.expr()), - code_hash: To(call_gadget.callee_code_hash.expr()), + code_hash: To(call_gadget.callee_code_hash.to_word()), gas_left: To(callee_gas_left), // For CALL opcode, `transfer` invocation has two account write if value is not // zero. @@ -489,7 +518,7 @@ impl ExecutionGadget for CallOpGadget { // get caller balance let (caller_balance, _) = block.get_rws(step, 17 + rw_offset).account_value_pair(); self.caller_balance_word - .assign(region, offset, Some(caller_balance.to_le_bytes()))?; + .assign_u256(region, offset, caller_balance)?; self.is_insufficient_balance .assign(region, offset, caller_balance, value)?; @@ -532,26 +561,12 @@ impl ExecutionGadget for CallOpGadget { call.rw_counter_end_of_reversion, call.is_persistent, )?; - self.current_callee_address.assign( - region, - offset, - Value::known( - current_callee_address - .to_scalar() - .expect("unexpected Address -> Scalar conversion failure"), - ), - )?; - self.current_caller_address.assign( - region, - offset, - Value::known( - current_caller_address - .to_scalar() - .expect("unexpected Address -> Scalar conversion failure"), - ), - )?; + self.current_callee_address + .assign_u256(region, offset, current_callee_address)?; + self.current_caller_address + .assign_u256(region, offset, current_caller_address)?; self.current_value - .assign(region, offset, Some(current_value.to_le_bytes()))?; + .assign_u256(region, offset, current_value)?; self.is_static .assign(region, offset, Value::known(F::from(is_static.low_u64())))?; self.depth diff --git a/zkevm-circuits/src/evm_circuit/execution/callvalue.rs b/zkevm-circuits/src/evm_circuit/execution/callvalue.rs index 237c954096..6486e01418 100644 --- a/zkevm-circuits/src/evm_circuit/execution/callvalue.rs +++ b/zkevm-circuits/src/evm_circuit/execution/callvalue.rs @@ -5,12 +5,15 @@ use crate::{ util::{ common_gadget::SameContextGadget, constraint_builder::{EVMConstraintBuilder, StepStateTransition, Transition::Delta}, - CachedRegion, Cell, + CachedRegion, }, witness::{Block, Call, ExecStep, Transaction}, }, table::CallContextFieldTag, - util::Expr, + util::{ + word::{WordCell, WordExpr}, + Expr, + }, }; use bus_mapping::evm::OpcodeId; use eth_types::Field; @@ -21,7 +24,7 @@ pub(crate) struct CallValueGadget { same_context: SameContextGadget, // Value in rw_table->stack_op and call_context->call_value are both RLC // encoded, so no need to decode. - call_value: Cell, + call_value: WordCell, } impl ExecutionGadget for CallValueGadget { @@ -30,18 +33,17 @@ impl ExecutionGadget for CallValueGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::CALLVALUE; fn configure(cb: &mut EVMConstraintBuilder) -> Self { - let call_value = cb.query_cell_phase2(); + let call_value = cb.query_word_unchecked(); // Lookup rw_table -> call_context with call value - cb.call_context_lookup( - false.expr(), + cb.call_context_lookup_read( None, // cb.curr.state.call_id CallContextFieldTag::Value, - call_value.expr(), + call_value.to_word(), ); // Push the value to the stack - cb.stack_push(call_value.expr()); + cb.stack_push_word(call_value.to_word()); // State transition let opcode = cb.query_cell(); @@ -73,8 +75,7 @@ impl ExecutionGadget for CallValueGadget { let call_value = block.get_rws(step, 1).stack_value(); - self.call_value - .assign(region, offset, region.word_rlc(call_value))?; + self.call_value.assign_u256(region, offset, call_value)?; Ok(()) } diff --git a/zkevm-circuits/src/evm_circuit/execution/chainid.rs b/zkevm-circuits/src/evm_circuit/execution/chainid.rs index e635b1e391..5a27fdc188 100644 --- a/zkevm-circuits/src/evm_circuit/execution/chainid.rs +++ b/zkevm-circuits/src/evm_circuit/execution/chainid.rs @@ -5,12 +5,15 @@ use crate::{ util::{ common_gadget::SameContextGadget, constraint_builder::{EVMConstraintBuilder, StepStateTransition, Transition::Delta}, - CachedRegion, Cell, + CachedRegion, }, witness::{Block, Call, ExecStep, Transaction}, }, table::BlockContextFieldTag, - util::Expr, + util::{ + word::{WordCell, WordExpr}, + Expr, + }, }; use bus_mapping::evm::OpcodeId; use eth_types::Field; @@ -19,7 +22,7 @@ use halo2_proofs::plonk::Error; #[derive(Clone, Debug)] pub(crate) struct ChainIdGadget { same_context: SameContextGadget, - chain_id: Cell, + chain_id: WordCell, } impl ExecutionGadget for ChainIdGadget { @@ -28,13 +31,17 @@ impl ExecutionGadget for ChainIdGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::CHAINID; fn configure(cb: &mut EVMConstraintBuilder) -> Self { - let chain_id = cb.query_cell_phase2(); + let chain_id = cb.query_word_unchecked(); // Push the value to the stack - cb.stack_push(chain_id.expr()); + cb.stack_push_word(chain_id.to_word()); // Lookup block table with chain_id - cb.block_lookup(BlockContextFieldTag::ChainId.expr(), None, chain_id.expr()); + cb.block_lookup_word( + BlockContextFieldTag::ChainId.expr(), + None, + chain_id.to_word(), + ); // State transition let opcode = cb.query_cell(); @@ -65,8 +72,7 @@ impl ExecutionGadget for ChainIdGadget { self.same_context.assign_exec_step(region, offset, step)?; let chain_id = block.get_rws(step, 0).stack_value(); - self.chain_id - .assign(region, offset, region.word_rlc(chain_id))?; + self.chain_id.assign_u256(region, offset, chain_id)?; Ok(()) } } diff --git a/zkevm-circuits/src/evm_circuit/execution/codecopy.rs b/zkevm-circuits/src/evm_circuit/execution/codecopy.rs index f47fef2936..6f1c65dbeb 100644 --- a/zkevm-circuits/src/evm_circuit/execution/codecopy.rs +++ b/zkevm-circuits/src/evm_circuit/execution/codecopy.rs @@ -16,7 +16,10 @@ use crate::{ }, witness::{Block, Call, ExecStep, Transaction}, }, - util::Expr, + util::{ + word::{Word, WordExpr}, + Expr, + }, }; use super::ExecutionGadget; @@ -53,23 +56,23 @@ impl ExecutionGadget for CodeCopyGadget { let code_size = cb.query_cell(); - let size = cb.query_word_rlc(); - let dst_memory_offset = cb.query_cell_phase2(); + let length = cb.query_memory_address(); + let dst_memory_offset = cb.query_word_unchecked(); let code_offset = WordByteCapGadget::construct(cb, code_size.expr()); // Pop items from stack. - cb.stack_pop(dst_memory_offset.expr()); - cb.stack_pop(code_offset.original_word()); - cb.stack_pop(size.expr()); + cb.stack_pop_word(dst_memory_offset.to_word()); + cb.stack_pop_word(code_offset.original_word_new().to_word()); + cb.stack_pop_word(Word::from_lo_unchecked(length.expr())); // Construct memory address in the destionation (memory) to which we copy code. - let dst_memory_addr = MemoryAddressGadget::construct(cb, dst_memory_offset, size); + let dst_memory_addr = MemoryAddressGadget::construct(cb, dst_memory_offset, length); // Fetch the hash of bytecode running in current environment. let code_hash = cb.curr.state.code_hash.clone(); // Fetch the bytecode length from the bytecode table. - cb.bytecode_length(code_hash.expr(), code_size.expr()); + cb.bytecode_length_word(code_hash.to_word(), code_size.expr()); // Calculate the next memory size and the gas cost for this memory // access. This also accounts for the dynamic gas required to copy bytes to @@ -91,9 +94,9 @@ impl ExecutionGadget for CodeCopyGadget { ); cb.copy_table_lookup( - code_hash.expr(), + code_hash.to_word(), CopyDataType::Bytecode.expr(), - cb.curr.state.call_id.expr(), + Word::from_lo_unchecked(cb.curr.state.call_id.expr()), CopyDataType::Memory.expr(), src_addr, code_size.expr(), diff --git a/zkevm-circuits/src/evm_circuit/execution/codesize.rs b/zkevm-circuits/src/evm_circuit/execution/codesize.rs index 86df028c24..383c3ba4c3 100644 --- a/zkevm-circuits/src/evm_circuit/execution/codesize.rs +++ b/zkevm-circuits/src/evm_circuit/execution/codesize.rs @@ -1,4 +1,3 @@ -use array_init::array_init; use bus_mapping::evm::OpcodeId; use eth_types::Field; use halo2_proofs::{circuit::Value, plonk::Error}; @@ -11,11 +10,11 @@ use crate::{ constraint_builder::{ ConstrainBuilderCommon, EVMConstraintBuilder, StepStateTransition, Transition, }, - from_bytes, CachedRegion, Cell, + CachedRegion, Cell, U64Cell, }, witness::{Block, Call, ExecStep, Transaction}, }, - util::Expr, + util::{word::WordExpr, Expr}, }; use super::ExecutionGadget; @@ -23,7 +22,7 @@ use super::ExecutionGadget; #[derive(Clone, Debug)] pub(crate) struct CodesizeGadget { same_context: SameContextGadget, - codesize_bytes: [Cell; 8], + codesize_bytes: U64Cell, codesize: Cell, } @@ -35,19 +34,19 @@ impl ExecutionGadget for CodesizeGadget { fn configure(cb: &mut EVMConstraintBuilder) -> Self { let opcode = cb.query_cell(); - let codesize_bytes = array_init(|_| cb.query_byte()); + let codesize_bytes = cb.query_u64(); let code_hash = cb.curr.state.code_hash.clone(); let codesize = cb.query_cell(); - cb.bytecode_length(code_hash.expr(), codesize.expr()); + cb.bytecode_length_word(code_hash.to_word(), codesize.expr()); cb.require_equal( "Constraint: bytecode length lookup == codesize", - from_bytes::expr(&codesize_bytes), + codesize_bytes.expr(), codesize.expr(), ); - cb.stack_push(cb.word_rlc(codesize_bytes.clone().map(|c| c.expr()))); + cb.stack_push_word(codesize_bytes.to_word()); let step_state_transition = StepStateTransition { gas_left: Transition::Delta(-OpcodeId::CODESIZE.constant_gas_cost().expr()), @@ -78,13 +77,8 @@ impl ExecutionGadget for CodesizeGadget { let codesize = block.get_rws(step, 0).stack_value().as_u64(); - for (c, b) in self - .codesize_bytes - .iter() - .zip(codesize.to_le_bytes().iter()) - { - c.assign(region, offset, Value::known(F::from(*b as u64)))?; - } + self.codesize_bytes + .assign(region, offset, Some(codesize.to_le_bytes()))?; self.codesize .assign(region, offset, Value::known(F::from(codesize)))?; diff --git a/zkevm-circuits/src/evm_circuit/execution/comparator.rs b/zkevm-circuits/src/evm_circuit/execution/comparator.rs index 9d593ef747..2df90a1be5 100644 --- a/zkevm-circuits/src/evm_circuit/execution/comparator.rs +++ b/zkevm-circuits/src/evm_circuit/execution/comparator.rs @@ -5,27 +5,28 @@ use crate::{ util::{ common_gadget::SameContextGadget, constraint_builder::{EVMConstraintBuilder, StepStateTransition, Transition::Delta}, - from_bytes, - math_gadget::{ComparisonGadget, IsEqualGadget}, - select, CachedRegion, Cell, Word, + math_gadget::{CmpWordsGadget, IsEqualGadget}, + select, CachedRegion, Cell, }, witness::{Block, Call, ExecStep, Transaction}, }, - util::Expr, + util::{ + word::{Word, WordCell, WordExpr}, + Expr, + }, }; -use eth_types::{evm_types::OpcodeId, Field, ToLittleEndian}; +use eth_types::{evm_types::OpcodeId, Field}; use halo2_proofs::{circuit::Value, plonk::Error}; #[derive(Clone, Debug)] pub(crate) struct ComparatorGadget { same_context: SameContextGadget, - a: Word, - b: Word, + a: WordCell, + b: WordCell, result: Cell, - comparison_lo: ComparisonGadget, - comparison_hi: ComparisonGadget, is_eq: IsEqualGadget, is_gt: IsEqualGadget, + word_comparison: CmpWordsGadget, WordCell>, } impl ExecutionGadget for ComparatorGadget { @@ -36,8 +37,8 @@ impl ExecutionGadget for ComparatorGadget { fn configure(cb: &mut EVMConstraintBuilder) -> Self { let opcode = cb.query_cell(); - let a = cb.query_word_rlc(); - let b = cb.query_word_rlc(); + let a = cb.query_word_unchecked(); + let b = cb.query_word_unchecked(); // Check if opcode is EQ let is_eq = IsEqualGadget::construct(cb, opcode.expr(), OpcodeId::EQ.expr()); @@ -45,42 +46,25 @@ impl ExecutionGadget for ComparatorGadget { // actually do greater than instead of smaller than. let is_gt = IsEqualGadget::construct(cb, opcode.expr(), OpcodeId::GT.expr()); - // `a[0..16] <= b[0..16]` - let comparison_lo = ComparisonGadget::construct( - cb, - from_bytes::expr(&a.cells[0..16]), - from_bytes::expr(&b.cells[0..16]), - ); - let (lt_lo, eq_lo) = comparison_lo.expr(); - - // `a[16..32] <= b[16..32]` - let comparison_hi = ComparisonGadget::construct( - cb, - from_bytes::expr(&a.cells[16..32]), - from_bytes::expr(&b.cells[16..32]), - ); - let (lt_hi, eq_hi) = comparison_hi.expr(); - - // `a < b` when: - // - `a[16..32] < b[16..32]` OR - // - `a[16..32] == b[16..32]` AND `a[0..16] < b[0..16]` - let lt = select::expr(lt_hi, 1.expr(), eq_hi.clone() * lt_lo); - // `a == b` when both parts are equal - let eq = eq_hi * eq_lo; + let word_comparison = CmpWordsGadget::construct(cb, a.clone(), b.clone()); // The result is: // - `lt` when LT or GT // - `eq` when EQ // Use copy to avoid degree too high for stack_push below. - let result = cb.copy(select::expr(is_eq.expr(), eq, lt)); + let result = cb.copy(select::expr( + is_eq.expr(), + word_comparison.eq.clone(), + word_comparison.lt.clone(), + )); // Pop a and b from the stack, push the result on the stack. // When swap is enabled we swap stack places between a and b. // We can push result here directly because // it only uses the LSB of a word. - cb.stack_pop(select::expr(is_gt.expr(), b.expr(), a.expr())); - cb.stack_pop(select::expr(is_gt.expr(), a.expr(), b.expr())); - cb.stack_push(result.expr()); + cb.stack_pop_word(Word::select(is_gt.expr(), b.to_word(), a.to_word())); + cb.stack_pop_word(Word::select(is_gt.expr(), a.to_word(), b.to_word())); + cb.stack_push_word(Word::from_lo_unchecked(result.expr())); // State transition let step_state_transition = StepStateTransition { @@ -96,9 +80,8 @@ impl ExecutionGadget for ComparatorGadget { same_context, a, b, + word_comparison, result, - comparison_lo, - comparison_hi, is_eq, is_gt, } @@ -134,27 +117,12 @@ impl ExecutionGadget for ComparatorGadget { )?; let indices = if is_gt == F::ONE { [1, 0] } else { [0, 1] }; - let [a, b] = indices.map(|index| block.get_rws(step, index).stack_value().to_le_bytes()); + let [a, b] = indices.map(|index| block.get_rws(step, index).stack_value()); let result = block.get_rws(step, 2).stack_value(); - // `a[0..16] <= b[0..16]` - self.comparison_lo.assign( - region, - offset, - from_bytes::value(&a[0..16]), - from_bytes::value(&b[0..16]), - )?; - - // `a[16..32] <= b[16..32]` - self.comparison_hi.assign( - region, - offset, - from_bytes::value(&a[16..32]), - from_bytes::value(&b[16..32]), - )?; - - self.a.assign(region, offset, Some(a))?; - self.b.assign(region, offset, Some(b))?; + self.word_comparison.assign(region, offset, a, b)?; + self.a.assign_u256(region, offset, a)?; + self.b.assign_u256(region, offset, b)?; self.result .assign(region, offset, Value::known(F::from(result.low_u64())))?; diff --git a/zkevm-circuits/src/evm_circuit/execution/create.rs b/zkevm-circuits/src/evm_circuit/execution/create.rs index 252e56c5d8..1292618ef4 100644 --- a/zkevm-circuits/src/evm_circuit/execution/create.rs +++ b/zkevm-circuits/src/evm_circuit/execution/create.rs @@ -13,24 +13,31 @@ use crate::{ Transition::{Delta, To}, }, math_gadget::{ - ConstantDivisionGadget, ContractCreateGadget, IsZeroGadget, LtGadget, LtWordGadget, + ConstantDivisionGadget, ContractCreateGadget, IsZeroGadget, IsZeroWordGadget, + LtGadget, LtWordGadget, }, memory_gadget::{MemoryAddressGadget, MemoryExpansionGadget}, - not, CachedRegion, Cell, Word, + not, AccountAddress, CachedRegion, Cell, Word, WordExpr, }, witness::{Block, Call, ExecStep, Transaction}, }, table::{AccountFieldTag, CallContextFieldTag}, - util::{word::Word32Cell, Expr}, + util::{ + word::{Word32Cell, WordCell}, + Expr, + }, }; use bus_mapping::{circuit_input_builder::CopyDataType, evm::OpcodeId, state_db::CodeDB}; use eth_types::{ evm_types::{GasCost, INIT_CODE_WORD_GAS}, - Field, ToBigEndian, ToLittleEndian, ToScalar, U256, + Field, ToBigEndian, ToScalar, U256, }; use ethers_core::utils::keccak256; -use gadgets::util::{and, expr_from_bytes, or, select}; -use halo2_proofs::{circuit::Value, plonk::Error}; +use gadgets::util::{and, or, select}; +use halo2_proofs::{ + circuit::Value, + plonk::{Error, Expression}, +}; use std::iter::once; @@ -47,22 +54,22 @@ pub(crate) struct CreateGadget, value: Word32Cell, - caller_balance: Word, + caller_balance: WordCell, callee_reversion_info: ReversionInfo, callee_nonce: Cell, - prev_code_hash: Cell, + prev_code_hash: WordCell, transfer: TransferGadget, create: ContractCreateGadget, init_code: MemoryAddressGadget, init_code_word_size: ConstantDivisionGadget, init_code_rlc: Cell, - keccak_output: Word, + keccak_output: Word32Cell, is_depth_in_range: LtGadget, is_insufficient_balance: LtWordGadget, is_nonce_in_range: LtGadget, - not_address_collision: IsZeroGadget, + not_address_collision: IsZeroWordGadget>>, memory_expansion: MemoryExpansionGadget, gas_left: ConstantDivisionGadget, @@ -95,50 +102,45 @@ impl ExecutionGadget< let depth = cb.call_context(None, CallContextFieldTag::Depth); let mut reversion_info = cb.reversion_info_read(None); - let keccak_output = cb.query_word_rlc(); + let keccak_output = cb.query_word32(); let create = ContractCreateGadget::construct(cb); - let contract_addr = expr_from_bytes(&keccak_output.cells[..N_BYTES_ACCOUNT_ADDRESS]); - let contract_addr_rlc = cb.word_rlc::( - keccak_output - .cells - .iter() - .take(N_BYTES_ACCOUNT_ADDRESS) - .map(Expr::expr) - .collect::>() + let contract_addr = AccountAddress::new( + keccak_output.limbs[..N_BYTES_ACCOUNT_ADDRESS] + .to_vec() .try_into() .unwrap(), ); // stack operations let value = cb.query_word32(); - let offset = cb.query_cell_phase2(); - let length = cb.query_word_rlc(); - cb.stack_pop(value.expr()); - cb.stack_pop(offset.expr()); - cb.stack_pop(length.expr()); + let length = cb.query_memory_address(); + let offset = cb.query_word_unchecked(); + cb.stack_pop_word(value.to_word()); + cb.stack_pop_word(offset.to_word()); + cb.stack_pop_word(length.to_word()); cb.condition(is_create2.expr(), |cb| { - cb.stack_pop(create.salt_word_rlc(cb).expr()); + cb.stack_pop_word(create.salt_word()); }); - cb.stack_push(is_success.expr() * contract_addr_rlc); + cb.stack_push_word(contract_addr.to_word().mul_selector(is_success.expr())); // read caller's balance and nonce let caller_nonce = create.caller_nonce(); - let caller_balance = cb.query_word_rlc(); - cb.account_read( - create.caller_address(), + let caller_balance = cb.query_word_unchecked(); + cb.account_read_word( + create.caller_address_word(), AccountFieldTag::Balance, - caller_balance.expr(), + caller_balance.to_word(), ); - cb.account_read( - create.caller_address(), + cb.account_read_word( + create.caller_address_word(), AccountFieldTag::Nonce, - caller_nonce.expr(), + Word::from_lo_unchecked(caller_nonce.expr()), ); // Pre-check: call depth, user's nonce and user's balance let is_depth_in_range = LtGadget::construct(cb, depth.expr(), 1025.expr()); let is_insufficient_balance = - LtWordGadget::construct(cb, &caller_balance, &value.clone().into()); + LtWordGadget::construct(cb, &caller_balance.to_word(), &value.to_word()); let is_nonce_in_range = LtGadget::construct(cb, caller_nonce.expr(), u64::MAX.expr()); let is_precheck_ok = and::expr([ is_depth_in_range.expr(), @@ -167,66 +169,79 @@ impl ExecutionGadget< let was_warm = cb.query_bool(); let init_code_rlc = cb.query_cell_phase2(); - let prev_code_hash = cb.query_cell(); + let prev_code_hash = cb.query_word_unchecked(); let callee_nonce = cb.query_cell(); let not_address_collision = cb.condition(is_precheck_ok.expr(), |cb| { // increase caller's nonce - cb.account_write( - create.caller_address(), + cb.account_write_word( + create.caller_address_word(), AccountFieldTag::Nonce, - caller_nonce.expr() + 1.expr(), - caller_nonce.expr(), + Word::from_lo_unchecked(caller_nonce.expr() + 1.expr()), + Word::from_lo_unchecked(caller_nonce.expr()), Some(&mut reversion_info), ); // add callee to access list - cb.account_access_list_write( + cb.account_access_list_write_unchecked( tx_id.expr(), - contract_addr.clone(), + contract_addr.to_word(), 1.expr(), was_warm.expr(), Some(&mut reversion_info), ); // read contract's previous hash - cb.account_read( - contract_addr.clone(), + cb.account_read_word( + contract_addr.to_word(), AccountFieldTag::CodeHash, - prev_code_hash.expr(), + prev_code_hash.to_word(), ); // ErrContractAddressCollision, if any one of following criteria meets. // Nonce is not zero or account code hash is not either 0 or EMPTY_CODE_HASH. - IsZeroGadget::construct( + // Here use `isZeroWord(callee_nonce + prev_code_hash_word * (prev_code_hash_word - + // empty_code_hash_word))` to represent `(callee_nonce == 0 && (prev_code_hash_word == 0 + // or prev_code_hash_word == empty_code_hash_word))` + let prev_code_hash_word = prev_code_hash.to_word(); + IsZeroWordGadget::construct( cb, - callee_nonce.expr() - + prev_code_hash.expr() * (prev_code_hash.expr() - cb.empty_code_hash_rlc()), + &Word::from_lo_unchecked(callee_nonce.expr()).add_unchecked( + prev_code_hash_word.clone().mul_unchecked( + prev_code_hash_word.sub_unchecked(cb.empty_code_hash_word()), + ), + ), ) }); for (field_tag, value) in [ ( CallContextFieldTag::ProgramCounter, - cb.curr.state.program_counter.expr() + 1.expr(), + Word::from_lo_unchecked(cb.curr.state.program_counter.expr() + 1.expr()), ), ( CallContextFieldTag::StackPointer, - cb.curr.state.stack_pointer.expr() + 2.expr() + is_create2.expr(), + Word::from_lo_unchecked( + cb.curr.state.stack_pointer.expr() + 2.expr() + is_create2.expr(), + ), + ), + ( + CallContextFieldTag::GasLeft, + Word::from_lo_unchecked(gas_left.quotient()), ), - (CallContextFieldTag::GasLeft, gas_left.quotient()), ( CallContextFieldTag::MemorySize, - memory_expansion.next_memory_word_size(), + Word::from_lo_unchecked(memory_expansion.next_memory_word_size()), ), ( CallContextFieldTag::ReversibleWriteCounter, - cb.curr.state.reversible_write_counter.expr() + 2.expr(), + Word::from_lo_unchecked(cb.curr.state.reversible_write_counter.expr() + 2.expr()), ), ] { - cb.call_context_lookup(true.expr(), None, field_tag, value); + cb.call_context_lookup_write(None, field_tag, value); } - let mut callee_reversion_info = cb.reversion_info_write(Some(callee_call_id.expr())); + let mut callee_reversion_info = + cb.reversion_info_write_unchecked(Some(callee_call_id.expr())); let transfer = cb.condition( and::expr([is_precheck_ok.clone(), not_address_collision.expr()]), |cb| { @@ -234,9 +249,9 @@ impl ExecutionGadget< // the init code is being copied from memory to bytecode, so a copy table lookup // to verify that the associated fields for the copy event. cb.copy_table_lookup( - current_call_id.expr(), + Word::from_lo_unchecked(current_call_id.expr()), CopyDataType::Memory.expr(), - create.code_hash_word_rlc(cb), + create.code_hash_word(), CopyDataType::Bytecode.expr(), init_code.offset(), init_code.address(), @@ -248,10 +263,10 @@ impl ExecutionGadget< }); // keccak table lookup to verify contract address. - cb.keccak_table_lookup( + cb.keccak_table_lookup_word( create.input_rlc(cb), create.input_length(), - keccak_output.expr(), + keccak_output.to_word(), ); // propagate is_persistent @@ -264,8 +279,8 @@ impl ExecutionGadget< // transfer let transfer = TransferGadget::construct( cb, - create.caller_address(), - contract_addr.clone(), + create.caller_address_word(), + contract_addr.to_word(), 0.expr(), 1.expr(), value.clone(), @@ -273,41 +288,62 @@ impl ExecutionGadget< ); // EIP 161, the nonce of a newly created contract is 1 - cb.account_write( - contract_addr.clone(), + cb.account_write_word( + contract_addr.to_word(), AccountFieldTag::Nonce, - 1.expr(), - 0.expr(), + Word::one(), + Word::zero(), Some(&mut callee_reversion_info), ); cb.condition(init_code.has_length(), |cb| { for (field_tag, value) in [ - (CallContextFieldTag::CallerId, current_call_id.expr()), - (CallContextFieldTag::IsSuccess, is_success.expr()), + ( + CallContextFieldTag::CallerId, + Word::from_lo_unchecked(current_call_id.expr()), + ), + ( + CallContextFieldTag::IsSuccess, + Word::from_lo_unchecked(is_success.expr()), + ), ( CallContextFieldTag::IsPersistent, - callee_reversion_info.is_persistent(), + Word::from_lo_unchecked(callee_reversion_info.is_persistent()), + ), + ( + CallContextFieldTag::TxId, + Word::from_lo_unchecked(tx_id.expr()), + ), + ( + CallContextFieldTag::CallerAddress, + create.caller_address_word(), ), - (CallContextFieldTag::TxId, tx_id.expr()), - (CallContextFieldTag::CallerAddress, create.caller_address()), - (CallContextFieldTag::CalleeAddress, contract_addr), + (CallContextFieldTag::CalleeAddress, contract_addr.to_word()), ( CallContextFieldTag::RwCounterEndOfReversion, - callee_reversion_info.rw_counter_end_of_reversion(), + Word::from_lo_unchecked( + callee_reversion_info.rw_counter_end_of_reversion(), + ), + ), + ( + CallContextFieldTag::Depth, + Word::from_lo_unchecked(depth.expr() + 1.expr()), ), - (CallContextFieldTag::Depth, depth.expr() + 1.expr()), - (CallContextFieldTag::IsRoot, false.expr()), - (CallContextFieldTag::IsStatic, false.expr()), - (CallContextFieldTag::IsCreate, true.expr()), - (CallContextFieldTag::CodeHash, create.code_hash_word_rlc(cb)), + ( + CallContextFieldTag::IsRoot, + Word::from_lo_unchecked(false.expr()), + ), + ( + CallContextFieldTag::IsStatic, + Word::from_lo_unchecked(false.expr()), + ), + ( + CallContextFieldTag::IsCreate, + Word::from_lo_unchecked(true.expr()), + ), + (CallContextFieldTag::CodeHash, create.code_hash_word()), ] { - cb.call_context_lookup( - true.expr(), - Some(callee_call_id.expr()), - field_tag, - value, - ); + cb.call_context_lookup_write(Some(callee_call_id.expr()), field_tag, value); } cb.require_step_state_transition(StepStateTransition { @@ -316,7 +352,7 @@ impl ExecutionGadget< call_id: To(callee_call_id.expr()), is_root: To(false.expr()), is_create: To(true.expr()), - code_hash: To(create.code_hash_word_rlc(cb)), + code_hash: To(create.code_hash_word()), gas_left: To(callee_gas_left), reversible_write_counter: To( 1.expr() + transfer.reversible_w_delta().expr() @@ -332,7 +368,7 @@ impl ExecutionGadget< CallContextFieldTag::LastCalleeReturnDataOffset, CallContextFieldTag::LastCalleeReturnDataLength, ] { - cb.call_context_lookup(true.expr(), None, field_tag, 0.expr()); + cb.call_context_lookup_write(None, field_tag, Word::zero()); } cb.require_step_state_transition(StepStateTransition { rw_counter: Delta(cb.rw_counter_offset()), @@ -375,7 +411,7 @@ impl ExecutionGadget< CallContextFieldTag::LastCalleeReturnDataOffset, CallContextFieldTag::LastCalleeReturnDataLength, ] { - cb.call_context_lookup(true.expr(), None, field_tag, 0.expr()); + cb.call_context_lookup_write(None, field_tag, Word::zero()); } cb.require_step_state_transition(StepStateTransition { @@ -454,8 +490,7 @@ impl ExecutionGadget< // stack value starts from 4 let [value, init_code_start, init_code_length] = [4, 5, 6].map(|idx| block.get_rws(step, idx).stack_value()); - self.value - .assign(region, offset, Some(value.to_le_bytes()))?; + self.value.assign_u256(region, offset, value)?; let salt = if is_create2 { block.get_rws(step, 7).stack_value() } else { @@ -474,7 +509,7 @@ impl ExecutionGadget< }; self.caller_balance - .assign(region, offset, Some(caller_balance.to_le_bytes()))?; + .assign_u256(region, offset, caller_balance)?; let (callee_prev_code_hash, was_warm) = if is_precheck_ok == 1 { let (_, was_warm) = block .get_rws(step, rw_offset + 4) @@ -496,17 +531,20 @@ impl ExecutionGadget< // retrieve code_hash for creating address let is_address_collision = !callee_prev_code_hash.is_zero(); - let code_hash_previous_rlc = if is_address_collision { - region.code_hash(callee_prev_code_hash) - } else { - Value::known(F::ZERO) - }; - self.prev_code_hash - .assign(region, offset, code_hash_previous_rlc)?; - self.not_address_collision.assign( + + self.prev_code_hash.assign_u256( region, offset, - F::from((is_address_collision).into()), + if is_address_collision { + callee_prev_code_hash + } else { + U256::from(0) + }, + )?; + self.not_address_collision.assign_u256( + region, + offset, + U256::from(is_address_collision as u8), )?; // gas cost of memory expansion @@ -583,8 +621,11 @@ impl ExecutionGadget< let mut keccak_output = keccak256(keccak_input); keccak_output.reverse(); - self.keccak_output - .assign(region, offset, Some(keccak_output))?; + self.keccak_output.assign_u256( + region, + offset, + U256::from_little_endian(&keccak_output), + )?; self.init_code_rlc.assign( region, offset, diff --git a/zkevm-circuits/src/evm_circuit/execution/dummy.rs b/zkevm-circuits/src/evm_circuit/execution/dummy.rs index eda17c468d..1388a023e2 100644 --- a/zkevm-circuits/src/evm_circuit/execution/dummy.rs +++ b/zkevm-circuits/src/evm_circuit/execution/dummy.rs @@ -4,18 +4,18 @@ use crate::{ evm_circuit::{ execution::ExecutionGadget, step::ExecutionState, - util::{constraint_builder::EVMConstraintBuilder, CachedRegion, Word}, + util::{constraint_builder::EVMConstraintBuilder, CachedRegion}, witness::{Block, Call, ExecStep, Transaction}, }, - util::Expr, + util::word::{WordCell, WordExpr}, }; -use eth_types::{Field, ToLittleEndian}; +use eth_types::Field; use halo2_proofs::plonk::Error; #[derive(Clone, Debug)] pub(crate) struct DummyGadget { - pops: [Word; N_POP], - pushes: [Word; N_PUSH], + pops: [WordCell; N_POP], + pushes: [WordCell; N_PUSH], _marker: PhantomData, } @@ -27,13 +27,13 @@ impl const EXECUTION_STATE: ExecutionState = S; fn configure(cb: &mut EVMConstraintBuilder) -> Self { - let pops: [Word; N_POP] = [(); N_POP].map(|_| cb.query_word_rlc()); - let pushes: [Word; N_PUSH] = [(); N_PUSH].map(|_| cb.query_word_rlc()); + let pops: [WordCell; N_POP] = [(); N_POP].map(|_| cb.query_word_unchecked()); + let pushes: [WordCell; N_PUSH] = [(); N_PUSH].map(|_| cb.query_word_unchecked()); for pop in pops.iter() { - cb.stack_pop(pop.expr()); + cb.stack_pop_word(pop.to_word()); } for push in pushes.iter() { - cb.stack_push(push.expr()); + cb.stack_push_word(push.to_word()); } Self { pops, @@ -61,11 +61,11 @@ impl for i in 0..N_POP { let value = block.get_rws(step, i).stack_value(); - self.pops[i].assign(region, offset, Some(value.to_le_bytes()))?; + self.pops[i].assign_u256(region, offset, value)?; } for i in 0..N_PUSH { let value = block.get_rws(step, N_POP + i).stack_value(); - self.pushes[i].assign(region, offset, Some(value.to_le_bytes()))?; + self.pushes[i].assign_u256(region, offset, value)?; } Ok(()) } diff --git a/zkevm-circuits/src/evm_circuit/execution/dup.rs b/zkevm-circuits/src/evm_circuit/execution/dup.rs index 9dc0816dd7..c3ebe5827b 100644 --- a/zkevm-circuits/src/evm_circuit/execution/dup.rs +++ b/zkevm-circuits/src/evm_circuit/execution/dup.rs @@ -5,11 +5,14 @@ use crate::{ util::{ common_gadget::SameContextGadget, constraint_builder::{EVMConstraintBuilder, StepStateTransition, Transition::Delta}, - CachedRegion, Cell, + CachedRegion, }, witness::{Block, Call, ExecStep, Transaction}, }, - util::Expr, + util::{ + word::{WordCell, WordExpr}, + Expr, + }, }; use eth_types::{evm_types::OpcodeId, Field}; use halo2_proofs::plonk::Error; @@ -17,7 +20,7 @@ use halo2_proofs::plonk::Error; #[derive(Clone, Debug)] pub(crate) struct DupGadget { same_context: SameContextGadget, - value: Cell, + value: WordCell, } impl ExecutionGadget for DupGadget { @@ -28,15 +31,15 @@ impl ExecutionGadget for DupGadget { fn configure(cb: &mut EVMConstraintBuilder) -> Self { let opcode = cb.query_cell(); - let value = cb.query_cell_phase2(); + let value = cb.query_word_unchecked(); // The stack index we have to peek, deduced from the 'x' value of 'dupx' // The offset starts at 0 for DUP1 let dup_offset = opcode.expr() - OpcodeId::DUP1.expr(); // Peek the value at `dup_offset` and push the value on the stack - cb.stack_lookup(false.expr(), dup_offset, value.expr()); - cb.stack_push(value.expr()); + cb.stack_lookup_word(false.expr(), dup_offset, value.to_word()); + cb.stack_push_word(value.to_word()); // State transition let step_state_transition = StepStateTransition { @@ -66,7 +69,7 @@ impl ExecutionGadget for DupGadget { self.same_context.assign_exec_step(region, offset, step)?; let value = block.get_rws(step, 0).stack_value(); - self.value.assign(region, offset, region.word_rlc(value))?; + self.value.assign_u256(region, offset, 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 4647efbce7..504af8cfb1 100644 --- a/zkevm-circuits/src/evm_circuit/execution/end_tx.rs +++ b/zkevm-circuits/src/evm_circuit/execution/end_tx.rs @@ -19,12 +19,12 @@ use crate::{ }, table::{BlockContextFieldTag, CallContextFieldTag, TxContextFieldTag, TxReceiptFieldTag}, util::{ - word::{Word, WordExpr}, + word::{Word, WordCell, WordExpr}, Expr, }, }; use bus_mapping::operation::Target; -use eth_types::{evm_types::MAX_REFUND_QUOTIENT_OF_GAS_USED, Field, ToScalar}; +use eth_types::{evm_types::MAX_REFUND_QUOTIENT_OF_GAS_USED, Field}; use halo2_proofs::{circuit::Value, plonk::Error}; use strum::EnumCount; @@ -36,11 +36,11 @@ pub(crate) struct EndTxGadget { refund: Cell, effective_refund: MinMaxGadget, mul_gas_price_by_refund: MulWordByU64Gadget, - tx_caller_address: Cell, + tx_caller_address: WordCell, gas_fee_refund: UpdateBalanceGadget, sub_gas_price_by_base_fee: AddWordsGadget, mul_effective_tip_by_gas_used: MulWordByU64Gadget, - coinbase: Cell, + coinbase: WordCell, coinbase_reward: UpdateBalanceGadget, current_cumulative_gas_used: Cell, is_first_tx: IsEqualGadget, @@ -56,9 +56,9 @@ impl ExecutionGadget for EndTxGadget { let tx_id = cb.call_context(None, CallContextFieldTag::TxId); let is_persistent = cb.call_context(None, CallContextFieldTag::IsPersistent); - let [tx_gas, tx_caller_address] = - [TxContextFieldTag::Gas, TxContextFieldTag::CallerAddress] - .map(|field_tag| cb.tx_context(tx_id.expr(), field_tag, None)); + let tx_gas = cb.tx_context(tx_id.expr(), TxContextFieldTag::Gas, None); + let tx_caller_address = + cb.tx_context_as_word(tx_id.expr(), TxContextFieldTag::CallerAddress, None); let tx_gas_price = cb.tx_context_as_word32(tx_id.expr(), TxContextFieldTag::GasPrice, None); // Calculate effective gas to refund @@ -80,32 +80,29 @@ impl ExecutionGadget for EndTxGadget { ); let gas_fee_refund = UpdateBalanceGadget::construct( cb, - tx_caller_address.expr(), + tx_caller_address.to_word(), vec![mul_gas_price_by_refund.product().clone()], None, ); // Add gas_used * effective_tip to coinbase's balance - let coinbase = cb.query_cell(); + let coinbase = cb.query_word_unchecked(); let base_fee = cb.query_word32(); // lookup && range check for (tag, value) in [ - ( - BlockContextFieldTag::Coinbase, - Word::from_lo_unchecked(coinbase.expr()), - ), + (BlockContextFieldTag::Coinbase, coinbase.to_word()), (BlockContextFieldTag::BaseFee, base_fee.to_word()), ] { cb.block_lookup_word(tag.expr(), None, value); } let effective_tip = cb.query_word32(); let sub_gas_price_by_base_fee = - AddWordsGadget::construct_new(cb, [effective_tip.clone(), base_fee], tx_gas_price); + AddWordsGadget::construct(cb, [effective_tip.clone(), base_fee], tx_gas_price); let mul_effective_tip_by_gas_used = MulWordByU64Gadget::construct(cb, effective_tip, gas_used.clone()); let coinbase_reward = UpdateBalanceGadget::construct( cb, - coinbase.expr(), + coinbase.to_word(), vec![mul_effective_tip_by_gas_used.product().clone()], None, ); @@ -153,7 +150,7 @@ impl ExecutionGadget for EndTxGadget { cb.condition( cb.next.execution_state_selector([ExecutionState::BeginTx]), |cb| { - cb.call_context_lookup_write_unchecked( + cb.call_context_lookup_write( Some(cb.next.state.rw_counter.expr()), CallContextFieldTag::TxId, // tx_id has been lookup and range_check above @@ -235,15 +232,8 @@ impl ExecutionGadget for EndTxGadget { effective_refund + step.gas_left, gas_fee_refund, )?; - self.tx_caller_address.assign( - region, - offset, - Value::known( - tx.caller_address - .to_scalar() - .expect("unexpected Address -> Scalar conversion failure"), - ), - )?; + self.tx_caller_address + .assign_h160(region, offset, tx.caller_address)?; self.gas_fee_refund.assign( region, offset, @@ -265,17 +255,8 @@ impl ExecutionGadget for EndTxGadget { gas_used, effective_tip * gas_used, )?; - self.coinbase.assign( - region, - offset, - Value::known( - block - .context - .coinbase - .to_scalar() - .expect("unexpected Address -> Scalar conversion failure"), - ), - )?; + self.coinbase + .assign_h160(region, offset, block.context.coinbase)?; self.coinbase_reward.assign( region, offset, 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 888c340aba..4e9e9e805c 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_invalid_jump.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_invalid_jump.rs @@ -6,12 +6,15 @@ use crate::{ util::{ common_gadget::{CommonErrorGadget, WordByteCapGadget}, constraint_builder::{ConstrainBuilderCommon, EVMConstraintBuilder}, - math_gadget::{IsEqualGadget, IsZeroGadget}, + math_gadget::{IsEqualGadget, IsZeroWordGadget}, CachedRegion, Cell, }, witness::{Block, Call, ExecStep, Transaction}, }, - util::Expr, + util::{ + word::{Word, WordCell, WordExpr}, + Expr, + }, }; use eth_types::{evm_types::OpcodeId, Field, ToWord, U256}; @@ -26,8 +29,8 @@ pub(crate) struct ErrorInvalidJumpGadget { is_code: Cell, is_jump_dest: IsEqualGadget, is_jumpi: IsEqualGadget, - phase2_condition: Cell, - is_condition_zero: IsZeroGadget, + condition: WordCell, + is_condition_zero: IsZeroWordGadget>, common_error_gadget: CommonErrorGadget, } @@ -43,7 +46,7 @@ impl ExecutionGadget for ErrorInvalidJumpGadget { let opcode = cb.query_cell(); let value = cb.query_cell(); let is_code = cb.query_cell(); - let phase2_condition = cb.query_cell_phase2(); + let condition = cb.query_word_unchecked(); cb.require_in_set( "ErrorInvalidJump only happend in JUMP or JUMPI", @@ -58,24 +61,24 @@ impl ExecutionGadget for ErrorInvalidJumpGadget { // first default this condition, if use will re-construct with real condition // value - let is_condition_zero = IsZeroGadget::construct(cb, phase2_condition.expr()); + let is_condition_zero = IsZeroWordGadget::construct(cb, &condition); // Pop the value from the stack - cb.stack_pop(dest.original_word()); + cb.stack_pop_word(dest.original_word_new().to_word()); cb.condition(is_jumpi.expr(), |cb| { - cb.stack_pop(phase2_condition.expr()); + cb.stack_pop_word(condition.to_word()); // if condition is zero, jump will not happen, so constrain condition not zero cb.require_zero("condition is not zero", is_condition_zero.expr()); }); // Look up bytecode length - cb.bytecode_length(cb.curr.state.code_hash.expr(), code_len.expr()); + cb.bytecode_length_word(cb.curr.state.code_hash.to_word(), code_len.expr()); // If destination is in valid range, lookup for the value. cb.condition(dest.lt_cap(), |cb| { - cb.bytecode_lookup( - cb.curr.state.code_hash.expr(), + cb.bytecode_lookup_word( + cb.curr.state.code_hash.to_word(), dest.valid_value(), is_code.expr(), value.expr(), @@ -97,7 +100,7 @@ impl ExecutionGadget for ErrorInvalidJumpGadget { is_code, is_jump_dest, is_jumpi, - phase2_condition, + condition, is_condition_zero, common_error_gadget, } @@ -122,7 +125,6 @@ impl ExecutionGadget for ErrorInvalidJumpGadget { } else { U256::zero() }; - let condition_rlc = region.word_rlc(condition); let code = block .bytecodes @@ -161,10 +163,9 @@ impl ExecutionGadget for ErrorInvalidJumpGadget { F::from(OpcodeId::JUMPI.as_u64()), )?; - self.phase2_condition - .assign(region, offset, condition_rlc)?; + self.condition.assign_u256(region, offset, condition)?; self.is_condition_zero - .assign_value(region, offset, condition_rlc)?; + .assign_value(region, offset, Value::known(Word::from(condition)))?; self.common_error_gadget.assign( region, 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 df949011e8..47fde088ac 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_oog_call.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_oog_call.rs @@ -66,7 +66,7 @@ impl ExecutionGadget for ErrorOOGCallGadget { let is_warm = cb.query_bool(); cb.account_access_list_read( tx_id.expr(), - call_gadget.callee_address_expr(), + call_gadget.callee_address_word(), is_warm.expr(), ); diff --git a/zkevm-circuits/src/evm_circuit/execution/error_oog_exp.rs b/zkevm-circuits/src/evm_circuit/execution/error_oog_exp.rs index 98c262f7b5..c261faa6a2 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_oog_exp.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_oog_exp.rs @@ -7,15 +7,18 @@ use crate::{ common_gadget::CommonErrorGadget, constraint_builder::{ConstrainBuilderCommon, EVMConstraintBuilder}, math_gadget::{ByteSizeGadget, LtGadget}, - CachedRegion, Cell, Word, + CachedRegion, Cell, }, witness::{Block, Call, ExecStep, Transaction}, }, - util::Expr, + util::{ + word::{Word32Cell, WordExpr}, + Expr, + }, }; use eth_types::{ evm_types::{GasCost, OpcodeId}, - Field, ToLittleEndian, + Field, }; use halo2_proofs::{circuit::Value, plonk::Error}; @@ -24,8 +27,8 @@ use halo2_proofs::{circuit::Value, plonk::Error}; #[derive(Clone, Debug)] pub(crate) struct ErrorOOGExpGadget { opcode: Cell, - base: Word, - exponent: Word, + base: Word32Cell, + exponent: Word32Cell, exponent_byte_size: ByteSizeGadget, insufficient_gas_cost: LtGadget, common_error_gadget: CommonErrorGadget, @@ -45,15 +48,15 @@ impl ExecutionGadget for ErrorOOGExpGadget { OpcodeId::EXP.expr(), ); - let base = cb.query_word_rlc(); - let exponent = cb.query_word_rlc(); - cb.stack_pop(base.expr()); - cb.stack_pop(exponent.expr()); + let base = cb.query_word32(); + let exponent = cb.query_word32(); + cb.stack_pop_word(base.to_word()); + cb.stack_pop_word(exponent.to_word()); let exponent_byte_size = ByteSizeGadget::construct( cb, exponent - .cells + .limbs .iter() .map(Expr::expr) .collect::>() @@ -108,9 +111,8 @@ impl ExecutionGadget for ErrorOOGExpGadget { self.opcode .assign(region, offset, Value::known(F::from(opcode.as_u64())))?; - self.base.assign(region, offset, Some(base.to_le_bytes()))?; - self.exponent - .assign(region, offset, Some(exponent.to_le_bytes()))?; + self.base.assign_u256(region, offset, base)?; + self.exponent.assign_u256(region, offset, exponent)?; self.exponent_byte_size.assign(region, offset, exponent)?; self.insufficient_gas_cost.assign_value( region, diff --git a/zkevm-circuits/src/evm_circuit/execution/error_oog_log.rs b/zkevm-circuits/src/evm_circuit/execution/error_oog_log.rs index 0892ce5958..8fae3291aa 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_oog_log.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_oog_log.rs @@ -13,7 +13,7 @@ use crate::{ witness::{Block, Call, ExecStep, Transaction}, }, table::CallContextFieldTag, - util::Expr, + util::{word::WordExpr, Expr}, }; use eth_types::{ evm_types::{GasCost, OpcodeId}, @@ -41,12 +41,12 @@ impl ExecutionGadget for ErrorOOGLogGadget { fn configure(cb: &mut EVMConstraintBuilder) -> Self { let opcode = cb.query_cell(); - let mstart = cb.query_cell_phase2(); - let msize = cb.query_word_rlc(); + let mstart = cb.query_word_unchecked(); + let msize = cb.query_memory_address(); // Pop mstart_address, msize from stack - cb.stack_pop(mstart.expr()); - cb.stack_pop(msize.expr()); + cb.stack_pop_word(mstart.to_word()); + cb.stack_pop_word(msize.to_word()); // constrain not in static call let is_static_call = cb.call_context(None, CallContextFieldTag::IsStatic); diff --git a/zkevm-circuits/src/evm_circuit/execution/error_oog_memory_copy.rs b/zkevm-circuits/src/evm_circuit/execution/error_oog_memory_copy.rs index 63499da840..81d142dc66 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_oog_memory_copy.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_oog_memory_copy.rs @@ -1,24 +1,26 @@ use crate::{ evm_circuit::{ execution::ExecutionGadget, - param::{N_BYTES_ACCOUNT_ADDRESS, N_BYTES_GAS, N_BYTES_MEMORY_WORD_SIZE}, + param::{N_BYTES_GAS, N_BYTES_MEMORY_WORD_SIZE}, step::ExecutionState, util::{ common_gadget::CommonErrorGadget, constraint_builder::{ConstrainBuilderCommon, EVMConstraintBuilder}, - from_bytes, math_gadget::{IsZeroGadget, LtGadget}, memory_gadget::{MemoryAddressGadget, MemoryCopierGasGadget, MemoryExpansionGadget}, - select, CachedRegion, Cell, Word, + select, AccountAddress, CachedRegion, Cell, }, witness::{Block, Call, ExecStep, Transaction}, }, table::CallContextFieldTag, - util::Expr, + util::{ + word::{Word, WordCell, WordExpr}, + Expr, + }, }; use eth_types::{ evm_types::{GasCost, OpcodeId}, - Field, ToLittleEndian, U256, + Field, U256, }; use halo2_proofs::{circuit::Value, plonk::Error}; @@ -32,9 +34,9 @@ pub(crate) struct ErrorOOGMemoryCopyGadget { is_warm: Cell, tx_id: Cell, /// Extra stack pop for `EXTCODECOPY` - external_address: Word, + external_address: AccountAddress, /// Source offset - src_offset: Word, + src_offset: WordCell, /// Destination offset and size to copy dst_memory_addr: MemoryAddressGadget, memory_expansion: MemoryExpansionGadget, @@ -62,10 +64,10 @@ impl ExecutionGadget for ErrorOOGMemoryCopyGadget { ], ); - let dst_offset = cb.query_cell_phase2(); - let src_offset = cb.query_word_rlc(); - let copy_size = cb.query_word_rlc(); - let external_address = cb.query_word_rlc(); + let dst_offset = cb.query_word_unchecked(); + let src_offset = cb.query_word_unchecked(); + let copy_size = cb.query_memory_address(); + let external_address = cb.query_account_address(); let is_warm = cb.query_bool(); let tx_id = cb.query_cell(); @@ -73,22 +75,22 @@ impl ExecutionGadget for ErrorOOGMemoryCopyGadget { IsZeroGadget::construct(cb, opcode.expr() - OpcodeId::EXTCODECOPY.expr()); cb.condition(is_extcodecopy.expr(), |cb| { - cb.call_context_lookup(false.expr(), None, CallContextFieldTag::TxId, tx_id.expr()); + cb.call_context_lookup_read( + None, + CallContextFieldTag::TxId, + Word::from_lo_unchecked(tx_id.expr()), + ); // Check if EXTCODECOPY external address is warm. - cb.account_access_list_read( - tx_id.expr(), - from_bytes::expr(&external_address.cells[..N_BYTES_ACCOUNT_ADDRESS]), - is_warm.expr(), - ); + cb.account_access_list_read(tx_id.expr(), external_address.to_word(), is_warm.expr()); // EXTCODECOPY has an extra stack pop for external address. - cb.stack_pop(external_address.expr()); + cb.stack_pop_word(external_address.to_word()); }); - cb.stack_pop(dst_offset.expr()); - cb.stack_pop(src_offset.expr()); - cb.stack_pop(copy_size.expr()); + cb.stack_pop_word(dst_offset.to_word()); + cb.stack_pop_word(src_offset.to_word()); + cb.stack_pop_word(copy_size.to_word()); let dst_memory_addr = MemoryAddressGadget::construct(cb, dst_offset, copy_size); let memory_expansion = MemoryExpansionGadget::construct(cb, [dst_memory_addr.address()]); @@ -185,9 +187,8 @@ impl ExecutionGadget for ErrorOOGMemoryCopyGadget { self.tx_id .assign(region, offset, Value::known(F::from(transaction.id as u64)))?; self.external_address - .assign(region, offset, Some(external_address.to_le_bytes()))?; - self.src_offset - .assign(region, offset, Some(src_offset.to_le_bytes()))?; + .assign_u256(region, offset, external_address)?; + self.src_offset.assign_u256(region, offset, src_offset)?; let memory_addr = self .dst_memory_addr .assign(region, offset, dst_offset, copy_size)?; diff --git a/zkevm-circuits/src/evm_circuit/execution/error_oog_sload_sstore.rs b/zkevm-circuits/src/evm_circuit/execution/error_oog_sload_sstore.rs index a17e9487f2..b3d3f1953e 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_oog_sload_sstore.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_oog_sload_sstore.rs @@ -16,11 +16,14 @@ use crate::{ witness::{Block, Call, ExecStep, Transaction}, }, table::CallContextFieldTag, - util::Expr, + util::{ + word::{Word, WordCell, WordExpr}, + Expr, + }, }; use eth_types::{ evm_types::{GasCost, OpcodeId}, - Field, ToScalar, U256, + Field, U256, }; use halo2_proofs::{circuit::Value, plonk::Error}; @@ -31,14 +34,14 @@ pub(crate) struct ErrorOOGSloadSstoreGadget { opcode: Cell, tx_id: Cell, is_static: Cell, - callee_address: Cell, - phase2_key: Cell, - phase2_value: Cell, - phase2_value_prev: Cell, - phase2_original_value: Cell, + callee_address: WordCell, + key: WordCell, + value: WordCell, + value_prev: WordCell, + original_value: WordCell, is_warm: Cell, is_sstore: PairSelectGadget, - sstore_gas_cost: SstoreGasGadget, + sstore_gas_cost: SstoreGasGadget>, insufficient_gas_cost: LtGadget, // Constrain for SSTORE reentrancy sentry. insufficient_gas_sentry: LtGadget, @@ -62,43 +65,43 @@ impl ExecutionGadget for ErrorOOGSloadSstoreGadget { let tx_id = cb.call_context(None, CallContextFieldTag::TxId); let is_static = cb.call_context(None, CallContextFieldTag::IsStatic); - let callee_address = cb.call_context(None, CallContextFieldTag::CalleeAddress); + let callee_address = cb.call_context_read_as_word(None, CallContextFieldTag::CalleeAddress); // Constrain `is_static` must be false for SSTORE. cb.require_zero("is_static == false", is_static.expr() * is_sstore.expr().0); - let phase2_key = cb.query_cell_phase2(); - let phase2_value = cb.query_cell_phase2(); - let phase2_value_prev = cb.query_cell_phase2(); - let phase2_original_value = cb.query_cell_phase2(); + let key = cb.query_word_unchecked(); + let value = cb.query_word_unchecked(); + let value_prev = cb.query_word_unchecked(); + let original_value = cb.query_word_unchecked(); let is_warm = cb.query_bool(); - cb.stack_pop(phase2_key.expr()); - cb.account_storage_access_list_read( + cb.stack_pop_word(key.to_word()); + cb.account_storage_access_list_read_word( tx_id.expr(), - callee_address.expr(), - phase2_key.expr(), - is_warm.expr(), + callee_address.to_word(), + key.to_word(), + Word::from_lo_unchecked(is_warm.expr()), ); let sload_gas_cost = SloadGasGadget::construct(cb, is_warm.expr()); let sstore_gas_cost = cb.condition(is_sstore.expr().0, |cb| { - cb.stack_pop(phase2_value.expr()); + cb.stack_pop_word(value.to_word()); - cb.account_storage_read( - callee_address.expr(), - phase2_key.expr(), - phase2_value_prev.expr(), + cb.account_storage_read_word( + callee_address.to_word(), + key.to_word(), + value_prev.to_word(), tx_id.expr(), - phase2_original_value.expr(), + original_value.to_word(), ); SstoreGasGadget::construct( cb, - phase2_value.clone(), - phase2_value_prev.clone(), - phase2_original_value.clone(), is_warm.clone(), + value.clone(), + value_prev.clone(), + original_value.clone(), ) }); @@ -137,10 +140,10 @@ impl ExecutionGadget for ErrorOOGSloadSstoreGadget { tx_id, is_static, callee_address, - phase2_key, - phase2_value, - phase2_value_prev, - phase2_original_value, + key, + value, + value_prev, + original_value, is_warm, is_sstore, sstore_gas_cost, @@ -189,23 +192,13 @@ impl ExecutionGadget for ErrorOOGSloadSstoreGadget { .assign(region, offset, Value::known(F::from(tx.id as u64)))?; self.is_static .assign(region, offset, Value::known(F::from(call.is_static as u64)))?; - self.callee_address.assign( - region, - offset, - Value::known( - call.address - .to_scalar() - .expect("unexpected Address -> Scalar conversion failure"), - ), - )?; - self.phase2_key - .assign(region, offset, region.word_rlc(key))?; - self.phase2_value - .assign(region, offset, region.word_rlc(value))?; - self.phase2_value_prev - .assign(region, offset, region.word_rlc(value_prev))?; - self.phase2_original_value - .assign(region, offset, region.word_rlc(original_value))?; + self.callee_address + .assign_h160(region, offset, call.address)?; + self.key.assign_u256(region, offset, key)?; + self.value.assign_u256(region, offset, value)?; + self.value_prev.assign_u256(region, offset, value_prev)?; + self.original_value + .assign_u256(region, offset, original_value)?; self.is_warm .assign(region, offset, Value::known(F::from(is_warm as u64)))?; 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 995913dbfd..03c60d422e 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_oog_static_memory.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_oog_static_memory.rs @@ -7,11 +7,14 @@ use crate::{ constraint_builder::EVMConstraintBuilder, math_gadget::{IsEqualGadget, IsZeroGadget, RangeCheckGadget}, memory_gadget::{address_high, address_low, MemoryExpansionGadget}, - CachedRegion, Cell, Word, + CachedRegion, Cell, }, witness::{Block, Call, ExecStep, Transaction}, }, - util::Expr, + util::{ + word::{Word32Cell, WordExpr}, + Expr, + }, }; use eth_types::{evm_types::OpcodeId, Field, ToLittleEndian}; use halo2_proofs::plonk::Error; @@ -19,7 +22,7 @@ use halo2_proofs::plonk::Error; #[derive(Clone, Debug)] pub(crate) struct ErrorOOGStaticMemoryGadget { opcode: Cell, - address: Word, + address: Word32Cell, address_in_range: IsZeroGadget, // Allow memory size to expand to 5 bytes, because memory address could be // at most 2^40 - 1, after constant division by 32, the memory word size @@ -45,7 +48,7 @@ impl ExecutionGadget for ErrorOOGStaticMemoryGadget { let opcode = cb.query_cell(); // Query address by a full word - let address = cb.query_word_rlc(); + let address = cb.query_word32(); // Check if this is an MSTORE8 let is_mstore8 = IsEqualGadget::construct(cb, opcode.expr(), OpcodeId::MSTORE8.expr()); @@ -54,11 +57,11 @@ impl ExecutionGadget for ErrorOOGStaticMemoryGadget { // Get the next memory size and the gas cost for this memory access let memory_expansion = MemoryExpansionGadget::construct( cb, - [address_low::expr(&address) + 1.expr() + (is_not_mstore8 * 31.expr())], + [address_low::expr_word(&address) + 1.expr() + (is_not_mstore8 * 31.expr())], ); // Check if the memory address is too large - let address_in_range = IsZeroGadget::construct(cb, address_high::expr(&address)); + let address_in_range = IsZeroGadget::construct(cb, address_high::expr_word(&address)); // Check if the amount of gas available is less than the amount of gas // required let insufficient_gas = cb.condition(address_in_range.expr(), |cb| { @@ -71,7 +74,7 @@ impl ExecutionGadget for ErrorOOGStaticMemoryGadget { // Pop the address from the stack // We still have to do this to verify the correctness of `address` - cb.stack_pop(address.expr()); + cb.stack_pop_word(address.to_word()); // TODO: Use ContextSwitchGadget to switch call context to caller's and // consume all gas_left. @@ -99,8 +102,7 @@ impl ExecutionGadget for ErrorOOGStaticMemoryGadget { // Inputs/Outputs let address = block.get_rws(step, 0).stack_value(); - self.address - .assign(region, offset, Some(address.to_le_bytes()))?; + self.address.assign_u256(region, offset, address)?; // Check if this is an MSTORE8 let is_mstore8 = self.is_mstore8.assign( diff --git a/zkevm-circuits/src/evm_circuit/execution/error_return_data_oo_bound.rs b/zkevm-circuits/src/evm_circuit/execution/error_return_data_oo_bound.rs index 5363dd2125..1d1d35bd9a 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_return_data_oo_bound.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_return_data_oo_bound.rs @@ -8,12 +8,15 @@ use crate::{ constraint_builder::{ConstrainBuilderCommon, EVMConstraintBuilder}, from_bytes, math_gadget::{AddWordsGadget, IsZeroGadget, LtGadget}, - not, or, sum, CachedRegion, Cell, + not, or, sum, CachedRegion, Cell, U64Cell, }, witness::{Block, Call, ExecStep, Transaction}, }, table::CallContextFieldTag, - util::Expr, + util::{ + word::{Word, WordExpr}, + Expr, + }, }; use eth_types::{evm_types::OpcodeId, Field, ToLittleEndian, ToScalar}; use halo2_proofs::{circuit::Value, plonk::Error}; @@ -21,7 +24,7 @@ use halo2_proofs::{circuit::Value, plonk::Error}; #[derive(Clone, Debug)] pub(crate) struct ErrorReturnDataOutOfBoundGadget { opcode: Cell, - memory_offset: Cell, + memory_offset: U64Cell, sum: AddWordsGadget, // Hold the size of the last callee return data. return_data_length: Cell, @@ -40,10 +43,10 @@ impl ExecutionGadget for ErrorReturnDataOutOfBoundGadget { fn configure(cb: &mut EVMConstraintBuilder) -> Self { let opcode = cb.query_cell(); - let memory_offset = cb.query_cell(); - let data_offset = cb.query_word_rlc(); - let size = cb.query_word_rlc(); - let remainder_end = cb.query_word_rlc(); + let memory_offset = cb.query_u64(); + let data_offset = cb.query_word32(); + let size = cb.query_word32(); + let remainder_end = cb.query_word32(); let return_data_length = cb.query_cell(); cb.require_equal( @@ -53,34 +56,33 @@ impl ExecutionGadget for ErrorReturnDataOutOfBoundGadget { ); // Pop memory_offset, offset, size from stack - cb.stack_pop(memory_offset.expr()); - cb.stack_pop(data_offset.expr()); - cb.stack_pop(size.expr()); + cb.stack_pop_word(memory_offset.to_word()); + cb.stack_pop_word(data_offset.to_word()); + cb.stack_pop_word(size.to_word()); // Read last callee return data length - cb.call_context_lookup( - false.expr(), + cb.call_context_lookup_read( None, CallContextFieldTag::LastCalleeReturnDataLength, - return_data_length.expr(), + Word::from_lo_unchecked(return_data_length.expr()), ); // Check if `data_offset` is Uint64 overflow. - let data_offset_larger_u64 = sum::expr(&data_offset.cells[N_BYTES_U64..]); + let data_offset_larger_u64 = sum::expr(&data_offset.limbs[N_BYTES_U64..]); let is_data_offset_within_u64 = IsZeroGadget::construct(cb, data_offset_larger_u64); // Check if `remainder_end` is Uint64 overflow. let sum = AddWordsGadget::construct(cb, [data_offset, size], remainder_end.clone()); let is_end_u256_overflow = sum.carry().as_ref().unwrap(); - let remainder_end_larger_u64 = sum::expr(&remainder_end.cells[N_BYTES_U64..]); + let remainder_end_larger_u64 = sum::expr(&remainder_end.limbs[N_BYTES_U64..]); let is_remainder_end_within_u64 = IsZeroGadget::construct(cb, remainder_end_larger_u64); // check if `remainder_end` exceeds return data length. let is_remainder_end_exceed_len = LtGadget::construct( cb, return_data_length.expr(), - from_bytes::expr(&remainder_end.cells[..N_BYTES_U64]), + from_bytes::expr(&remainder_end.limbs[..N_BYTES_U64]), ); // Need to check if `data_offset + size` is U256 overflow via `AddWordsGadget` carry. If @@ -132,7 +134,7 @@ impl ExecutionGadget for ErrorReturnDataOutOfBoundGadget { [0, 1, 2].map(|index| block.get_rws(step, index).stack_value()); self.memory_offset - .assign(region, offset, Value::known(F::from(dest_offset.as_u64())))?; + .assign(region, offset, Some(dest_offset.as_u64().to_le_bytes()))?; let remainder_end = data_offset.overflowing_add(size).0; self.sum diff --git a/zkevm-circuits/src/evm_circuit/execution/error_write_protection.rs b/zkevm-circuits/src/evm_circuit/execution/error_write_protection.rs index 0f1fbe7a0c..d428e8b742 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_write_protection.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_write_protection.rs @@ -5,25 +5,28 @@ use crate::{ util::{ common_gadget::CommonErrorGadget, constraint_builder::{ConstrainBuilderCommon, EVMConstraintBuilder}, - math_gadget::IsZeroGadget, - sum, CachedRegion, Cell, Word as RLCWord, + math_gadget::{IsZeroGadget, IsZeroWordGadget}, + AccountAddress, CachedRegion, Cell, }, witness::{Block, Call, ExecStep, Transaction}, }, table::CallContextFieldTag, - util::Expr, + util::{ + word::{Word, WordCell, WordExpr}, + Expr, + }, }; -use eth_types::{evm_types::OpcodeId, Field, ToLittleEndian, U256}; +use eth_types::{evm_types::OpcodeId, Field, U256}; use halo2_proofs::{circuit::Value, plonk::Error}; #[derive(Clone, Debug)] pub(crate) struct ErrorWriteProtectionGadget { opcode: Cell, is_call: IsZeroGadget, - gas: RLCWord, - code_address: RLCWord, - value: RLCWord, - is_value_zero: IsZeroGadget, + gas: WordCell, + code_address: AccountAddress, + value: WordCell, + is_value_zero: IsZeroWordGadget>, common_error_gadget: CommonErrorGadget, } @@ -35,10 +38,10 @@ impl ExecutionGadget for ErrorWriteProtectionGadget { fn configure(cb: &mut EVMConstraintBuilder) -> Self { let opcode = cb.query_cell(); let is_call = IsZeroGadget::construct(cb, opcode.expr() - OpcodeId::CALL.expr()); - let gas_word = cb.query_word_rlc(); - let code_address_word = cb.query_word_rlc(); - let value = cb.query_word_rlc(); - let is_value_zero = IsZeroGadget::construct(cb, value.expr()); + let gas_word = cb.query_word_unchecked(); + let code_address = cb.query_account_address(); + let value = cb.query_word_unchecked(); + let is_value_zero = IsZeroWordGadget::construct(cb, &value); // require_in_set method will spilit into more low degree expressions if exceed // max_degree. otherwise need to do fixed lookup for these opcodes @@ -63,14 +66,14 @@ impl ExecutionGadget for ErrorWriteProtectionGadget { // Lookup values from stack if opcode is call // Precondition: If there's a StackUnderflow CALL, is handled before this error cb.condition(is_call.expr(), |cb| { - cb.stack_pop(gas_word.expr()); - cb.stack_pop(code_address_word.expr()); - cb.stack_pop(value.expr()); + cb.stack_pop_word(gas_word.to_word()); + cb.stack_pop_word(code_address.to_word()); + cb.stack_pop_word(value.to_word()); cb.require_zero("value of call is not zero", is_value_zero.expr()); }); // current call context is readonly - cb.call_context_lookup(false.expr(), None, CallContextFieldTag::IsStatic, 1.expr()); + cb.call_context_lookup_read(None, CallContextFieldTag::IsStatic, Word::one()); // constrain not root call as at least one previous staticcall preset. cb.require_zero( @@ -84,7 +87,7 @@ impl ExecutionGadget for ErrorWriteProtectionGadget { opcode, is_call, gas: gas_word, - code_address: code_address_word, + code_address, value, is_value_zero, common_error_gadget, @@ -111,11 +114,10 @@ impl ExecutionGadget for ErrorWriteProtectionGadget { [0, 1, 2].map(|index| block.get_rws(step, index).stack_value()); } - self.gas.assign(region, offset, Some(gas.to_le_bytes()))?; + self.gas.assign_u256(region, offset, gas)?; self.code_address - .assign(region, offset, Some(code_address.to_le_bytes()))?; - self.value - .assign(region, offset, Some(value.to_le_bytes()))?; + .assign_u256(region, offset, code_address)?; + self.value.assign_u256(region, offset, value)?; self.is_call.assign( region, @@ -123,7 +125,7 @@ impl ExecutionGadget for ErrorWriteProtectionGadget { F::from(opcode.as_u64()) - F::from(OpcodeId::CALL.as_u64()), )?; self.is_value_zero - .assign(region, offset, sum::value(&value.to_le_bytes()))?; + .assign(region, offset, Word::from(value))?; self.common_error_gadget.assign( region, diff --git a/zkevm-circuits/src/evm_circuit/execution/exp.rs b/zkevm-circuits/src/evm_circuit/execution/exp.rs index 5a1f8dd4e3..2e8b3eac36 100644 --- a/zkevm-circuits/src/evm_circuit/execution/exp.rs +++ b/zkevm-circuits/src/evm_circuit/execution/exp.rs @@ -1,20 +1,25 @@ use bus_mapping::evm::OpcodeId; -use eth_types::{evm_types::GasCost, Field, ToLittleEndian, ToScalar, U256}; -use gadgets::util::{and, not, split_u256, sum, Expr}; -use halo2_proofs::{circuit::Value, plonk::Error}; +use eth_types::{evm_types::GasCost, Field, ToScalar, U256}; +use gadgets::util::{and, not, split_u256, Expr}; +use halo2_proofs::{ + circuit::Value, + plonk::{Error, Expression}, +}; -use crate::evm_circuit::{ - step::ExecutionState, - util::{ - common_gadget::SameContextGadget, - constraint_builder::{ - ConstrainBuilderCommon, EVMConstraintBuilder, StepStateTransition, Transition, +use crate::{ + evm_circuit::{ + step::ExecutionState, + util::{ + common_gadget::SameContextGadget, + constraint_builder::{ + ConstrainBuilderCommon, EVMConstraintBuilder, StepStateTransition, Transition, + }, + math_gadget::{ByteSizeGadget, IsEqualGadget, IsZeroGadget}, + CachedRegion, Cell, }, - from_bytes, - math_gadget::{ByteSizeGadget, IsEqualGadget, IsZeroGadget}, - CachedRegion, Cell, Word, + witness::{Block, Call, ExecStep, Transaction}, }, - witness::{Block, Call, ExecStep, Transaction}, + util::word::{Word32Cell, Word4, WordExpr}, }; use super::ExecutionGadget; @@ -24,15 +29,13 @@ pub(crate) struct ExponentiationGadget { /// Gadget to check that we stay within the same context. same_context: SameContextGadget, /// RLC-encoded integer base that will be exponentiated. - base: Word, + base: Word32Cell, /// RLC-encoded representation for base * base, i.e. base^2 - base_sq: Word, - /// RLC-encoded representation for zero. - zero_rlc: Word, + base_sq: Word32Cell, /// RLC-encoded exponent for the exponentiation operation. - exponent: Word, + exponent: Word32Cell, /// RLC-encoded result of the exponentiation. - exponentiation: Word, + exponentiation: Word32Cell, /// Gadget to check if low 128-bit part of exponent is zero or not. exponent_lo_is_zero: IsZeroGadget, /// Gadget to check if high 128-bit part of exponent is zero or not. @@ -55,32 +58,23 @@ 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_word_rlc(); - let exponent_rlc = cb.query_word_rlc(); - let exponentiation_rlc = cb.query_word_rlc(); + let base = cb.query_word32(); + let exponent = cb.query_word32(); + let exponentiation = cb.query_word32(); // Pop RLC-encoded base and exponent from the stack. - cb.stack_pop(base_rlc.expr()); - cb.stack_pop(exponent_rlc.expr()); + cb.stack_pop_word(base.to_word()); + cb.stack_pop_word(exponent.to_word()); // Push RLC-encoded exponentiation to the stack. - cb.stack_push(exponentiation_rlc.expr()); + cb.stack_push_word(exponentiation.to_word()); // Extract low and high bytes of the base. - let (base_lo, base_hi) = ( - from_bytes::expr(&base_rlc.cells[0x00..0x10]), - from_bytes::expr(&base_rlc.cells[0x10..0x20]), - ); + let (base_lo, base_hi) = base.to_word().to_lo_hi(); // Extract low and high bytes of the exponent. - let (exponent_lo, exponent_hi) = ( - from_bytes::expr(&exponent_rlc.cells[0x00..0x10]), - from_bytes::expr(&exponent_rlc.cells[0x10..0x20]), - ); + let (exponent_lo, exponent_hi) = exponent.to_word().to_lo_hi(); // Extract low and high bytes of the exponentiation result. - let (exponentiation_lo, exponentiation_hi) = ( - from_bytes::expr(&exponentiation_rlc.cells[0x00..0x10]), - from_bytes::expr(&exponentiation_rlc.cells[0x10..0x20]), - ); + let (exponentiation_lo, exponentiation_hi) = exponentiation.to_word().to_lo_hi(); // We simplify constraints depending on whether or not the exponent is 0 or 1. // In order to do this, we build some utility expressions. @@ -92,12 +86,7 @@ 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_rlc(); - cb.require_zero( - "base * base + c == base^2 (c == 0)", - sum::expr(&zero_rlc.cells), - ); - let base_sq = cb.query_word_rlc(); + let base_sq = cb.query_word32(); // If exponent == 0, base^exponent == 1, which implies: // 1. Low bytes of exponentiation == 1 @@ -140,23 +129,15 @@ impl ExecutionGadget for ExponentiationGadget { not::expr(exponent_is_one_expr), ]), |cb| { - let base_limbs = [ - from_bytes::expr(&base_rlc.cells[0x00..0x08]), - from_bytes::expr(&base_rlc.cells[0x08..0x10]), - from_bytes::expr(&base_rlc.cells[0x10..0x18]), - from_bytes::expr(&base_rlc.cells[0x18..0x20]), - ]; - let (base_sq_lo, base_sq_hi) = ( - from_bytes::expr(&base_sq.cells[0x00..0x10]), - from_bytes::expr(&base_sq.cells[0x10..0x20]), - ); + let base_limbs: Word4> = base.to_word_n(); + let (base_sq_lo, base_sq_hi) = base_sq.to_word().to_lo_hi(); let identifier = cb.curr.state.rw_counter.expr() + cb.rw_counter_offset(); // lookup for first step, i.e. // (is_last, base, exponent, exponentiation) cb.exp_table_lookup( identifier.clone(), single_step.expr(), - base_limbs.clone(), + base_limbs.limbs.clone(), [exponent_lo.clone(), exponent_hi.clone()], [exponentiation_lo.clone(), exponentiation_hi.clone()], ); @@ -164,7 +145,7 @@ impl ExecutionGadget for ExponentiationGadget { cb.exp_table_lookup( identifier, 1.expr(), - base_limbs, + base_limbs.limbs, [2.expr(), 0.expr()], // exponent == 2 [base_sq_lo.expr(), base_sq_hi.expr()], ); @@ -174,16 +155,7 @@ impl ExecutionGadget for ExponentiationGadget { // In order to calculate the dynamic gas cost of the exponentiation operation, // we need the byte-size of the exponent, i.e. the minimum number of // bytes that can represent the exponent value. - let exponent_byte_size = ByteSizeGadget::construct( - cb, - exponent_rlc - .cells - .iter() - .map(Expr::expr) - .collect::>() - .try_into() - .unwrap(), - ); + let exponent_byte_size = ByteSizeGadget::construct(cb, exponent.to_word_n().limbs); // Finally we build an expression for the dynamic gas cost as: // dynamic_gas = 50 * exponent_byte_size @@ -202,11 +174,10 @@ impl ExecutionGadget for ExponentiationGadget { Self { same_context, - base: base_rlc, + base, base_sq, - zero_rlc, - exponent: exponent_rlc, - exponentiation: exponentiation_rlc, + exponent, + exponentiation, exponent_lo_is_zero, exponent_hi_is_zero, exponent_lo_is_one, @@ -229,11 +200,10 @@ impl ExecutionGadget for ExponentiationGadget { let [base, exponent, exponentiation] = [0, 1, 2].map(|index| block.get_rws(step, index).stack_value()); - self.base.assign(region, offset, Some(base.to_le_bytes()))?; - self.exponent - .assign(region, offset, Some(exponent.to_le_bytes()))?; + self.base.assign_u256(region, offset, base)?; + self.exponent.assign_u256(region, offset, exponent)?; self.exponentiation - .assign(region, offset, Some(exponentiation.to_le_bytes()))?; + .assign_u256(region, offset, exponentiation)?; let (exponent_lo, exponent_hi) = split_u256(&exponent); let exponent_lo_scalar = exponent_lo @@ -250,10 +220,7 @@ impl ExecutionGadget for ExponentiationGadget { .assign(region, offset, exponent_lo_scalar, F::ONE)?; let (base_sq, _) = base.overflowing_mul(base); - self.zero_rlc - .assign(region, offset, Some(U256::zero().to_le_bytes()))?; - self.base_sq - .assign(region, offset, Some(base_sq.to_le_bytes()))?; + self.base_sq.assign_u256(region, offset, base_sq)?; let single_step = exponent.eq(&U256::from(2u64)); self.single_step .assign(region, offset, Value::known(F::from(single_step as u64)))?; diff --git a/zkevm-circuits/src/evm_circuit/execution/extcodecopy.rs b/zkevm-circuits/src/evm_circuit/execution/extcodecopy.rs index 49a24fbb44..2b80d9dcf6 100644 --- a/zkevm-circuits/src/evm_circuit/execution/extcodecopy.rs +++ b/zkevm-circuits/src/evm_circuit/execution/extcodecopy.rs @@ -8,33 +8,36 @@ use crate::{ ConstrainBuilderCommon, EVMConstraintBuilder, ReversionInfo, StepStateTransition, Transition, }, - from_bytes, - math_gadget::IsZeroGadget, + math_gadget::IsZeroWordGadget, memory_gadget::{MemoryAddressGadget, MemoryCopierGasGadget, MemoryExpansionGadget}, - not, select, CachedRegion, Cell, Word, + not, select, AccountAddress, CachedRegion, Cell, }, witness::{Block, Call, ExecStep, Transaction}, }, table::{AccountFieldTag, CallContextFieldTag}, + util::word::{Word, Word32Cell, WordExpr}, }; use bus_mapping::circuit_input_builder::CopyDataType; -use eth_types::{evm_types::GasCost, Field, ToLittleEndian, ToScalar}; +use eth_types::{evm_types::GasCost, Field, ToScalar}; use gadgets::util::Expr; -use halo2_proofs::{circuit::Value, plonk::Error}; +use halo2_proofs::{ + circuit::Value, + plonk::{Error, Expression}, +}; use super::ExecutionGadget; #[derive(Clone, Debug)] pub(crate) struct ExtcodecopyGadget { same_context: SameContextGadget, - external_address_word: Word, + external_address_word: Word32Cell, memory_address: MemoryAddressGadget, code_offset: WordByteCapGadget, tx_id: Cell, reversion_info: ReversionInfo, is_warm: Cell, - code_hash: Cell, - not_exists: IsZeroGadget, + code_hash: Word32Cell, + not_exists: IsZeroWordGadget>>, code_size: Cell, copy_rwc_inc: Cell, memory_expansion: MemoryExpansionGadget, @@ -49,42 +52,46 @@ impl ExecutionGadget for ExtcodecopyGadget { fn configure(cb: &mut EVMConstraintBuilder) -> Self { let opcode = cb.query_cell(); - let external_address_word = cb.query_word_rlc(); - let external_address = - from_bytes::expr(&external_address_word.cells[..N_BYTES_ACCOUNT_ADDRESS]); + let external_address_word = cb.query_word32(); + let external_address = AccountAddress::new( + external_address_word.limbs[..N_BYTES_ACCOUNT_ADDRESS] + .to_vec() + .try_into() + .unwrap(), + ); let code_size = cb.query_cell(); - let memory_length = cb.query_word_rlc(); - let memory_offset = cb.query_cell_phase2(); + let memory_length = cb.query_memory_address(); + let memory_offset = cb.query_word_unchecked(); let code_offset = WordByteCapGadget::construct(cb, code_size.expr()); - cb.stack_pop(external_address_word.expr()); - cb.stack_pop(memory_offset.expr()); - cb.stack_pop(code_offset.original_word()); - cb.stack_pop(memory_length.expr()); + cb.stack_pop_word(external_address_word.to_word()); + cb.stack_pop_word(memory_offset.to_word()); + cb.stack_pop_word(code_offset.original_word_new().to_word()); + cb.stack_pop_word(memory_length.to_word()); let tx_id = cb.call_context(None, CallContextFieldTag::TxId); let mut reversion_info = cb.reversion_info_read(None); let is_warm = cb.query_bool(); - cb.account_access_list_write( + cb.account_access_list_write_unchecked( tx_id.expr(), - external_address.expr(), + external_address.to_word(), 1.expr(), is_warm.expr(), Some(&mut reversion_info), ); - let code_hash = cb.query_cell_phase2(); - cb.account_read( - external_address.expr(), + let code_hash = cb.query_word32(); + cb.account_read_word( + external_address.to_word(), AccountFieldTag::CodeHash, - code_hash.expr(), + code_hash.to_word(), ); - let not_exists = IsZeroGadget::construct(cb, code_hash.expr()); + let not_exists = IsZeroWordGadget::construct(cb, &code_hash.to_word()); let exists = not::expr(not_exists.expr()); cb.condition(exists.expr(), |cb| { - cb.bytecode_length(code_hash.expr(), code_size.expr()); + cb.bytecode_length_word(code_hash.to_word(), code_size.expr()); }); cb.condition(not_exists.expr(), |cb| { cb.require_zero("code_size is zero when non_exists", code_size.expr()); @@ -114,9 +121,9 @@ impl ExecutionGadget for ExtcodecopyGadget { ); cb.copy_table_lookup( - code_hash.expr(), + code_hash.to_word(), CopyDataType::Bytecode.expr(), - cb.curr.state.call_id.expr(), + Word::from_lo_unchecked(cb.curr.state.call_id.expr()), CopyDataType::Memory.expr(), src_addr, code_size.expr(), @@ -175,7 +182,7 @@ impl ExecutionGadget for ExtcodecopyGadget { let [external_address, memory_offset, code_offset, memory_length] = [0, 1, 2, 3].map(|idx| block.get_rws(step, idx).stack_value()); self.external_address_word - .assign(region, offset, Some(external_address.to_le_bytes()))?; + .assign_u256(region, offset, external_address)?; let memory_address = self.memory_address .assign(region, offset, memory_offset, memory_length)?; @@ -194,10 +201,8 @@ impl ExecutionGadget for ExtcodecopyGadget { .assign(region, offset, Value::known(F::from(is_warm as u64)))?; let code_hash = block.get_rws(step, 8).account_value_pair().0; - self.code_hash - .assign(region, offset, region.word_rlc(code_hash))?; - self.not_exists - .assign_value(region, offset, region.word_rlc(code_hash))?; + self.code_hash.assign_u256(region, offset, code_hash)?; + self.not_exists.assign_u256(region, offset, code_hash)?; let code_size = if code_hash.is_zero() { 0 diff --git a/zkevm-circuits/src/evm_circuit/execution/extcodehash.rs b/zkevm-circuits/src/evm_circuit/execution/extcodehash.rs index 1d14cffa34..caca0f704f 100644 --- a/zkevm-circuits/src/evm_circuit/execution/extcodehash.rs +++ b/zkevm-circuits/src/evm_circuit/execution/extcodehash.rs @@ -8,24 +8,27 @@ use crate::{ constraint_builder::{ EVMConstraintBuilder, ReversionInfo, StepStateTransition, Transition::Delta, }, - from_bytes, select, CachedRegion, Cell, Word, + select, AccountAddress, CachedRegion, Cell, }, witness::{Block, Call, ExecStep, Transaction}, }, table::{AccountFieldTag, CallContextFieldTag}, - util::Expr, + util::{ + word::{Word32Cell, WordCell, WordExpr}, + Expr, + }, }; -use eth_types::{evm_types::GasCost, Field, ToLittleEndian}; +use eth_types::{evm_types::GasCost, Field}; use halo2_proofs::{circuit::Value, plonk::Error}; #[derive(Clone, Debug)] pub(crate) struct ExtcodehashGadget { same_context: SameContextGadget, - address_word: Word, + address_word: Word32Cell, tx_id: Cell, reversion_info: ReversionInfo, is_warm: Cell, - code_hash: Cell, + code_hash: WordCell, } impl ExecutionGadget for ExtcodehashGadget { @@ -34,26 +37,36 @@ impl ExecutionGadget for ExtcodehashGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::EXTCODEHASH; fn configure(cb: &mut EVMConstraintBuilder) -> Self { - 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()); + let address_word = cb.query_word32(); + let address = AccountAddress::new( + address_word.limbs[..N_BYTES_ACCOUNT_ADDRESS] + .to_vec() + .try_into() + .unwrap(), + ); + cb.stack_pop_word(address_word.to_word()); let tx_id = cb.call_context(None, CallContextFieldTag::TxId); let mut reversion_info = cb.reversion_info_read(None); let is_warm = cb.query_bool(); - cb.account_access_list_write( + cb.account_access_list_write_unchecked( tx_id.expr(), - address.expr(), + address.to_word(), 1.expr(), is_warm.expr(), Some(&mut reversion_info), ); - let code_hash = cb.query_cell_phase2(); + // range check will be cover by account code_hash lookup + let code_hash = cb.query_word_unchecked(); // For non-existing accounts the code_hash must be 0 in the rw_table. - cb.account_read(address, AccountFieldTag::CodeHash, code_hash.expr()); - cb.stack_push(code_hash.expr()); + cb.account_read_word( + address.to_word(), + AccountFieldTag::CodeHash, + code_hash.to_word(), + ); + cb.stack_push_word(code_hash.to_word()); let gas_cost = select::expr( is_warm.expr(), @@ -94,8 +107,7 @@ impl ExecutionGadget for ExtcodehashGadget { self.same_context.assign_exec_step(region, offset, step)?; let address = block.get_rws(step, 0).stack_value(); - self.address_word - .assign(region, offset, Some(address.to_le_bytes()))?; + self.address_word.assign_u256(region, offset, address)?; self.tx_id .assign(region, offset, Value::known(F::from(tx.id as u64)))?; @@ -111,8 +123,7 @@ impl ExecutionGadget for ExtcodehashGadget { .assign(region, offset, Value::known(F::from(is_warm as u64)))?; let code_hash = block.get_rws(step, 5).account_value_pair().0; - self.code_hash - .assign(region, offset, region.word_rlc(code_hash))?; + self.code_hash.assign_u256(region, offset, code_hash)?; Ok(()) } diff --git a/zkevm-circuits/src/evm_circuit/execution/extcodesize.rs b/zkevm-circuits/src/evm_circuit/execution/extcodesize.rs index 8c00bd63c7..273bec425f 100644 --- a/zkevm-circuits/src/evm_circuit/execution/extcodesize.rs +++ b/zkevm-circuits/src/evm_circuit/execution/extcodesize.rs @@ -1,7 +1,7 @@ use crate::{ evm_circuit::{ execution::ExecutionGadget, - param::{N_BYTES_ACCOUNT_ADDRESS, N_BYTES_U64}, + param::N_BYTES_ACCOUNT_ADDRESS, step::ExecutionState, util::{ common_gadget::SameContextGadget, @@ -9,28 +9,30 @@ use crate::{ ConstrainBuilderCommon, EVMConstraintBuilder, ReversionInfo, StepStateTransition, Transition::Delta, }, - from_bytes, - math_gadget::IsZeroGadget, - not, select, CachedRegion, Cell, RandomLinearCombination, Word, + math_gadget::IsZeroWordGadget, + not, select, AccountAddress, CachedRegion, Cell, U64Cell, }, witness::{Block, Call, ExecStep, Transaction}, }, table::{AccountFieldTag, CallContextFieldTag}, - util::Expr, + util::{ + word::{Word, Word32Cell, WordCell, WordExpr}, + Expr, + }, }; -use eth_types::{evm_types::GasCost, Field, ToLittleEndian}; +use eth_types::{evm_types::GasCost, Field}; use halo2_proofs::{circuit::Value, plonk::Error}; #[derive(Clone, Debug)] pub(crate) struct ExtcodesizeGadget { same_context: SameContextGadget, - address_word: Word, + address_word: Word32Cell, reversion_info: ReversionInfo, tx_id: Cell, is_warm: Cell, - code_hash: Cell, - not_exists: IsZeroGadget, - code_size: RandomLinearCombination, + code_hash: WordCell, + not_exists: IsZeroWordGadget>, + code_size: U64Cell, } impl ExecutionGadget for ExtcodesizeGadget { @@ -39,36 +41,46 @@ impl ExecutionGadget for ExtcodesizeGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::EXTCODESIZE; fn configure(cb: &mut EVMConstraintBuilder) -> Self { - 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()); + let address_word = cb.query_word32(); + let address = AccountAddress::new( + address_word.limbs[..N_BYTES_ACCOUNT_ADDRESS] + .to_vec() + .try_into() + .unwrap(), + ); + cb.stack_pop_word(address_word.to_word()); let tx_id = cb.call_context(None, CallContextFieldTag::TxId); let mut reversion_info = cb.reversion_info_read(None); let is_warm = cb.query_bool(); - cb.account_access_list_write( + cb.account_access_list_write_unchecked( tx_id.expr(), - address.expr(), + address.to_word(), 1.expr(), is_warm.expr(), Some(&mut reversion_info), ); - let code_hash = cb.query_cell_phase2(); + // range check will be cover by account code_hash lookup + let code_hash = cb.query_word_unchecked(); // For non-existing accounts the code_hash must be 0 in the rw_table. - cb.account_read(address.expr(), AccountFieldTag::CodeHash, code_hash.expr()); - let not_exists = IsZeroGadget::construct(cb, code_hash.expr()); + cb.account_read_word( + address.to_word(), + AccountFieldTag::CodeHash, + code_hash.to_word(), + ); + let not_exists = IsZeroWordGadget::construct(cb, &code_hash); let exists = not::expr(not_exists.expr()); - let code_size = cb.query_word_rlc(); + let code_size = cb.query_u64(); cb.condition(exists.expr(), |cb| { - cb.bytecode_length(code_hash.expr(), from_bytes::expr(&code_size.cells)); + cb.bytecode_length_word(code_hash.to_word(), code_size.expr()); }); cb.condition(not_exists.expr(), |cb| { cb.require_zero("code_size is zero when non_exists", code_size.expr()); }); - cb.stack_push(code_size.expr()); + cb.stack_push_word(code_size.to_word()); let gas_cost = select::expr( is_warm.expr(), @@ -112,8 +124,7 @@ impl ExecutionGadget for ExtcodesizeGadget { self.same_context.assign_exec_step(region, offset, step)?; let address = block.get_rws(step, 0).stack_value(); - self.address_word - .assign(region, offset, Some(address.to_le_bytes()))?; + self.address_word.assign_u256(region, offset, address)?; self.tx_id .assign(region, offset, Value::known(F::from(tx.id as u64)))?; @@ -130,10 +141,9 @@ impl ExecutionGadget for ExtcodesizeGadget { .assign(region, offset, Value::known(F::from(is_warm as u64)))?; let code_hash = block.get_rws(step, 5).account_value_pair().0; - self.code_hash - .assign(region, offset, region.word_rlc(code_hash))?; + self.code_hash.assign_u256(region, offset, code_hash)?; self.not_exists - .assign_value(region, offset, region.word_rlc(code_hash))?; + .assign(region, offset, Word::from(code_hash))?; let code_size = block.get_rws(step, 6).stack_value().as_u64(); self.code_size diff --git a/zkevm-circuits/src/evm_circuit/execution/gas.rs b/zkevm-circuits/src/evm_circuit/execution/gas.rs index f8151dc7ca..d2e992199e 100644 --- a/zkevm-circuits/src/evm_circuit/execution/gas.rs +++ b/zkevm-circuits/src/evm_circuit/execution/gas.rs @@ -1,7 +1,6 @@ use crate::{ evm_circuit::{ execution::ExecutionGadget, - param::N_BYTES_GAS, step::ExecutionState, util::{ common_gadget::SameContextGadget, @@ -9,11 +8,11 @@ use crate::{ ConstrainBuilderCommon, EVMConstraintBuilder, StepStateTransition, Transition::Delta, }, - from_bytes, CachedRegion, RandomLinearCombination, + CachedRegion, U64Cell, }, witness::{Block, Call, ExecStep, Transaction}, }, - util::Expr, + util::{word::WordExpr, Expr}, }; use eth_types::{evm_types::OpcodeId, Field}; use halo2_proofs::plonk::Error; @@ -21,7 +20,7 @@ use halo2_proofs::plonk::Error; #[derive(Clone, Debug)] pub(crate) struct GasGadget { same_context: SameContextGadget, - gas_left: RandomLinearCombination, + gas_left: U64Cell, } impl ExecutionGadget for GasGadget { @@ -31,18 +30,18 @@ impl ExecutionGadget for GasGadget { fn configure(cb: &mut EVMConstraintBuilder) -> Self { // The gas passed to a transaction is a 64-bit number. - let gas_left = cb.query_word_rlc(); + let gas_left = cb.query_u64(); // The `gas_left` in the current state has to be deducted by the gas // used by the `GAS` opcode itself. cb.require_equal( "Constraint: gas left equal to stack value", - from_bytes::expr(&gas_left.cells), + gas_left.expr(), cb.curr.state.gas_left.expr() - OpcodeId::GAS.constant_gas_cost().expr(), ); // Construct the value and push it to stack. - cb.stack_push(gas_left.expr()); + cb.stack_push_word(gas_left.to_word()); let step_state_transition = StepStateTransition { rw_counter: Delta(1.expr()), diff --git a/zkevm-circuits/src/evm_circuit/execution/gasprice.rs b/zkevm-circuits/src/evm_circuit/execution/gasprice.rs index 2e6c5561cb..3fcd9e8aca 100644 --- a/zkevm-circuits/src/evm_circuit/execution/gasprice.rs +++ b/zkevm-circuits/src/evm_circuit/execution/gasprice.rs @@ -10,7 +10,10 @@ use crate::{ witness::{Block, Call, ExecStep, Transaction}, }, table::{CallContextFieldTag, TxContextFieldTag}, - util::Expr, + util::{ + word::{WordCell, WordExpr}, + Expr, + }, }; use bus_mapping::evm::OpcodeId; use eth_types::Field; @@ -19,7 +22,7 @@ use halo2_proofs::{circuit::Value, plonk::Error}; #[derive(Clone, Debug)] pub(crate) struct GasPriceGadget { tx_id: Cell, - gas_price: Cell, + gas_price: WordCell, same_context: SameContextGadget, } @@ -30,20 +33,20 @@ impl ExecutionGadget for GasPriceGadget { fn configure(cb: &mut EVMConstraintBuilder) -> Self { // Query gasprice value - let gas_price = cb.query_cell_phase2(); + let gas_price = cb.query_word_unchecked(); // Lookup in call_ctx the TxId let tx_id = cb.call_context(None, CallContextFieldTag::TxId); // Lookup the gas_price in tx table - cb.tx_context_lookup( + cb.tx_context_lookup_word( tx_id.expr(), TxContextFieldTag::GasPrice, None, - gas_price.expr(), + gas_price.to_word(), ); // Push the value to the stack - cb.stack_push(gas_price.expr()); + cb.stack_push_word(gas_price.to_word()); // State transition let opcode = cb.query_cell(); @@ -77,8 +80,7 @@ impl ExecutionGadget for GasPriceGadget { self.tx_id .assign(region, offset, Value::known(F::from(tx.id as u64)))?; - self.gas_price - .assign(region, offset, region.word_rlc(gas_price))?; + self.gas_price.assign_u256(region, offset, 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 36671e5f5a..f0b4fc237a 100644 --- a/zkevm-circuits/src/evm_circuit/execution/is_zero.rs +++ b/zkevm-circuits/src/evm_circuit/execution/is_zero.rs @@ -5,21 +5,24 @@ use crate::{ util::{ common_gadget::SameContextGadget, constraint_builder::{EVMConstraintBuilder, StepStateTransition, Transition::Delta}, - math_gadget, CachedRegion, Cell, + math_gadget, CachedRegion, }, witness::{Block, Call, ExecStep, Transaction}, }, - util::Expr, + util::{ + word::{Word, WordCell, WordExpr}, + Expr, + }, }; use bus_mapping::evm::OpcodeId; use eth_types::Field; -use halo2_proofs::plonk::Error; +use halo2_proofs::{circuit::Value, plonk::Error}; #[derive(Clone, Debug)] pub(crate) struct IsZeroGadget { same_context: SameContextGadget, - value: Cell, - is_zero: math_gadget::IsZeroGadget, + value: WordCell, + is_zero_word: math_gadget::IsZeroWordGadget>, } impl ExecutionGadget for IsZeroGadget { @@ -30,11 +33,11 @@ impl ExecutionGadget for IsZeroGadget { fn configure(cb: &mut EVMConstraintBuilder) -> Self { let opcode = cb.query_cell(); - let value = cb.query_cell_phase2(); - let is_zero = math_gadget::IsZeroGadget::construct(cb, value.expr()); + let value = cb.query_word_unchecked(); + let is_zero_word = math_gadget::IsZeroWordGadget::construct(cb, &value); - cb.stack_pop(value.expr()); - cb.stack_push(is_zero.expr()); + cb.stack_pop_word(value.to_word()); + cb.stack_push_word(Word::from_lo_unchecked(is_zero_word.expr())); // State transition let step_state_transition = StepStateTransition { @@ -49,7 +52,7 @@ impl ExecutionGadget for IsZeroGadget { Self { same_context, value, - is_zero, + is_zero_word, } } @@ -65,9 +68,9 @@ impl ExecutionGadget for IsZeroGadget { self.same_context.assign_exec_step(region, offset, step)?; let value = block.get_rws(step, 0).stack_value(); - let value = region.word_rlc(value); - self.value.assign(region, offset, value)?; - self.is_zero.assign_value(region, offset, value)?; + self.value.assign_u256(region, offset, value)?; + self.is_zero_word + .assign_value(region, offset, Value::known(Word::from(value)))?; Ok(()) } diff --git a/zkevm-circuits/src/evm_circuit/execution/jump.rs b/zkevm-circuits/src/evm_circuit/execution/jump.rs index fc03df544b..af644d01ab 100644 --- a/zkevm-circuits/src/evm_circuit/execution/jump.rs +++ b/zkevm-circuits/src/evm_circuit/execution/jump.rs @@ -1,7 +1,6 @@ use crate::{ evm_circuit::{ execution::ExecutionGadget, - param::N_BYTES_PROGRAM_COUNTER, step::ExecutionState, util::{ common_gadget::SameContextGadget, @@ -9,19 +8,19 @@ use crate::{ EVMConstraintBuilder, StepStateTransition, Transition::{Delta, To}, }, - from_bytes, CachedRegion, RandomLinearCombination, + CachedRegion, U64Cell, }, witness::{Block, Call, ExecStep, Transaction}, }, - util::Expr, + util::{word::WordExpr, Expr}, }; -use eth_types::{evm_types::OpcodeId, Field, ToLittleEndian}; +use eth_types::{evm_types::OpcodeId, Field}; use halo2_proofs::plonk::Error; #[derive(Clone, Debug)] pub(crate) struct JumpGadget { same_context: SameContextGadget, - destination: RandomLinearCombination, + destination: U64Cell, } impl ExecutionGadget for JumpGadget { @@ -30,23 +29,19 @@ impl ExecutionGadget for JumpGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::JUMP; fn configure(cb: &mut EVMConstraintBuilder) -> Self { - let destination = cb.query_word_rlc(); + let destination = cb.query_u64(); // Pop the value from the stack - cb.stack_pop(destination.expr()); + cb.stack_pop_word(destination.to_word()); // Lookup opcode at destination - cb.opcode_lookup_at( - from_bytes::expr(&destination.cells), - OpcodeId::JUMPDEST.expr(), - 1.expr(), - ); + cb.opcode_lookup_at(destination.expr(), OpcodeId::JUMPDEST.expr(), 1.expr()); // State transition let opcode = cb.query_cell(); let step_state_transition = StepStateTransition { rw_counter: Delta(1.expr()), - program_counter: To(from_bytes::expr(&destination.cells)), + program_counter: To(destination.expr()), stack_pointer: Delta(1.expr()), gas_left: Delta(-OpcodeId::JUMP.constant_gas_cost().expr()), ..Default::default() @@ -71,15 +66,7 @@ impl ExecutionGadget for JumpGadget { self.same_context.assign_exec_step(region, offset, step)?; let destination = block.get_rws(step, 0).stack_value(); - self.destination.assign( - region, - offset, - Some( - destination.to_le_bytes()[..N_BYTES_PROGRAM_COUNTER] - .try_into() - .unwrap(), - ), - )?; + self.destination.assign_u256(region, offset, destination)?; Ok(()) } diff --git a/zkevm-circuits/src/evm_circuit/execution/jumpi.rs b/zkevm-circuits/src/evm_circuit/execution/jumpi.rs index 8c131e21e5..a8bdb36e85 100644 --- a/zkevm-circuits/src/evm_circuit/execution/jumpi.rs +++ b/zkevm-circuits/src/evm_circuit/execution/jumpi.rs @@ -9,22 +9,25 @@ use crate::{ ConstrainBuilderCommon, EVMConstraintBuilder, StepStateTransition, Transition::{Delta, To}, }, - math_gadget::IsZeroGadget, - select, CachedRegion, Cell, + math_gadget::IsZeroWordGadget, + select, CachedRegion, }, witness::{Block, Call, ExecStep, Transaction}, }, - util::Expr, + util::{ + word::{Word, WordCell, WordExpr}, + Expr, + }, }; use eth_types::{evm_types::OpcodeId, Field}; -use halo2_proofs::plonk::Error; +use halo2_proofs::{circuit::Value, plonk::Error}; #[derive(Clone, Debug)] pub(crate) struct JumpiGadget { same_context: SameContextGadget, dest: WordByteRangeGadget, - phase2_condition: Cell, - is_condition_zero: IsZeroGadget, + condition: WordCell, + is_condition_zero: IsZeroWordGadget>, } impl ExecutionGadget for JumpiGadget { @@ -34,14 +37,14 @@ impl ExecutionGadget for JumpiGadget { fn configure(cb: &mut EVMConstraintBuilder) -> Self { let dest = WordByteRangeGadget::construct(cb); - let phase2_condition = cb.query_cell_phase2(); + let condition = cb.query_word_unchecked(); // Pop the value from the stack - cb.stack_pop(dest.original_word()); - cb.stack_pop(phase2_condition.expr()); + cb.stack_pop_word(dest.original()); + cb.stack_pop_word(condition.to_word()); // Determine if the jump condition is met - let is_condition_zero = IsZeroGadget::construct(cb, phase2_condition.expr()); + let is_condition_zero = IsZeroWordGadget::construct(cb, &condition); let should_jump = 1.expr() - is_condition_zero.expr(); // Lookup opcode at destination when should_jump @@ -77,7 +80,7 @@ impl ExecutionGadget for JumpiGadget { Self { same_context, dest, - phase2_condition, + condition, is_condition_zero, } } @@ -94,12 +97,11 @@ impl ExecutionGadget for JumpiGadget { self.same_context.assign_exec_step(region, offset, step)?; let [destination, condition] = [0, 1].map(|index| block.get_rws(step, index).stack_value()); - let condition = region.word_rlc(condition); self.dest.assign(region, offset, destination)?; - self.phase2_condition.assign(region, offset, condition)?; + self.condition.assign_u256(region, offset, condition)?; self.is_condition_zero - .assign_value(region, offset, condition)?; + .assign_value(region, offset, Value::known(Word::from(condition)))?; Ok(()) } diff --git a/zkevm-circuits/src/evm_circuit/execution/logs.rs b/zkevm-circuits/src/evm_circuit/execution/logs.rs index 77f1c7d66e..0c4f8fe6f6 100644 --- a/zkevm-circuits/src/evm_circuit/execution/logs.rs +++ b/zkevm-circuits/src/evm_circuit/execution/logs.rs @@ -15,7 +15,11 @@ use crate::{ witness::{Block, Call, ExecStep, Transaction}, }, table::{CallContextFieldTag, TxLogFieldTag}, - util::{build_tx_log_expression, word::Word, Expr}, + util::{ + build_tx_log_expression, + word::{Word, Word32Cell, WordCell, WordExpr}, + Expr, + }, }; use array_init::array_init; use bus_mapping::circuit_input_builder::CopyDataType; @@ -30,10 +34,10 @@ pub(crate) struct LogGadget { same_context: SameContextGadget, // memory address memory_address: MemoryAddressGadget, - phase2_topics: [Cell; 4], + topics: [Word32Cell; 4], topic_selectors: [Cell; 4], - contract_address: Cell, + contract_address: WordCell, is_static_call: Cell, is_persistent: Cell, tx_id: Cell, @@ -47,12 +51,12 @@ impl ExecutionGadget for LogGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::LOG; fn configure(cb: &mut EVMConstraintBuilder) -> Self { - let mstart = cb.query_cell_phase2(); - let msize = cb.query_word_rlc(); + let mstart = cb.query_word_unchecked(); + let msize = cb.query_memory_address(); // Pop mstart_address, msize from stack - cb.stack_pop(mstart.expr()); - cb.stack_pop(msize.expr()); + cb.stack_pop_word(mstart.to_word()); + cb.stack_pop_word(msize.to_word()); // read tx id let tx_id = cb.call_context(None, CallContextFieldTag::TxId); // constrain not in static call @@ -61,34 +65,35 @@ impl ExecutionGadget for LogGadget { // check contract_address in CallContext & TxLog // use call context's callee address as contract address - let contract_address = cb.call_context(None, CallContextFieldTag::CalleeAddress); + let contract_address = + cb.call_context_read_as_word(None, CallContextFieldTag::CalleeAddress); let is_persistent = cb.call_context(None, CallContextFieldTag::IsPersistent); cb.require_boolean("is_persistent is bool", is_persistent.expr()); cb.condition(is_persistent.expr(), |cb| { - cb.tx_log_lookup( + cb.tx_log_lookup_word( tx_id.expr(), cb.curr.state.log_id.expr() + 1.expr(), TxLogFieldTag::Address, 0.expr(), - contract_address.expr(), + contract_address.to_word(), ); }); // constrain topics in logs - let phase2_topics = array_init(|_| cb.query_cell_phase2()); + let topics = array_init(|_| cb.query_word32()); let topic_selectors: [Cell; 4] = array_init(|_| cb.query_cell()); - for (idx, topic) in phase2_topics.iter().enumerate() { + for (idx, topic) in topics.iter().enumerate() { cb.condition(topic_selectors[idx].expr(), |cb| { - cb.stack_pop_word(Word::from_lo_unchecked(topic.expr())); + cb.stack_pop_word(topic.to_word()); }); cb.condition(topic_selectors[idx].expr() * is_persistent.expr(), |cb| { - cb.tx_log_lookup( + cb.tx_log_lookup_word( tx_id.expr(), cb.curr.state.log_id.expr() + 1.expr(), TxLogFieldTag::Topic, idx.expr(), - topic.expr(), + topic.to_word(), ); }); } @@ -132,9 +137,9 @@ impl ExecutionGadget for LogGadget { let cond = memory_address.has_length() * is_persistent.expr(); cb.condition(cond.clone(), |cb| { cb.copy_table_lookup( - cb.curr.state.call_id.expr(), + Word::from_lo_unchecked(cb.curr.state.call_id.expr()), CopyDataType::Memory.expr(), - tx_id.expr(), + Word::from_lo_unchecked(tx_id.expr()), CopyDataType::TxLog.expr(), memory_address.offset(), memory_address.address(), @@ -172,7 +177,7 @@ impl ExecutionGadget for LogGadget { Self { same_context, memory_address, - phase2_topics, + topics, topic_selectors, contract_address, is_static_call, @@ -225,22 +230,11 @@ impl ExecutionGadget for LogGadget { offset, Value::known(F::from(topic.is_some().into())), )?; - self.phase2_topics[i].assign( - region, - offset, - region.word_rlc(topic.unwrap_or_default()), - )?; + self.topics[i].assign_u256(region, offset, topic.unwrap_or_default())?; } - self.contract_address.assign( - region, - offset, - Value::known( - call.address - .to_scalar() - .expect("unexpected Address -> Scalar conversion failure"), - ), - )?; + self.contract_address + .assign_h160(region, offset, call.address)?; let is_persistent = call.is_persistent as u64; self.is_static_call .assign(region, offset, Value::known(F::from(call.is_static as u64)))?; diff --git a/zkevm-circuits/src/evm_circuit/execution/memory.rs b/zkevm-circuits/src/evm_circuit/execution/memory.rs index fc33c9e7bc..e120e4be06 100644 --- a/zkevm-circuits/src/evm_circuit/execution/memory.rs +++ b/zkevm-circuits/src/evm_circuit/execution/memory.rs @@ -20,7 +20,7 @@ use crate::{ Expr, }, }; -use eth_types::{evm_types::OpcodeId, Field, ToLittleEndian}; +use eth_types::{evm_types::OpcodeId, Field}; use halo2_proofs::plonk::Error; #[derive(Clone, Debug)] @@ -58,7 +58,7 @@ impl ExecutionGadget for MemoryGadget { // access let memory_expansion = MemoryExpansionGadget::construct( cb, - [address.to_word().lo() + 1.expr() + (is_not_mstore8.clone() * 31.expr())], + [address.expr() + 1.expr() + (is_not_mstore8.clone() * 31.expr())], ); // Stack operations @@ -73,19 +73,14 @@ impl ExecutionGadget for MemoryGadget { ); cb.condition(is_mstore8.expr(), |cb| { - cb.memory_lookup( - 1.expr(), - address.to_word().lo(), - value.limbs[0].expr(), - None, - ); + cb.memory_lookup(1.expr(), address.expr(), value.limbs[0].expr(), None); }); cb.condition(is_not_mstore8, |cb| { for idx in 0..32 { cb.memory_lookup( is_store.clone(), - address.to_word().lo().clone() + idx.expr(), + address.expr() + idx.expr(), value.limbs[31 - idx].expr(), None, ); @@ -134,13 +129,8 @@ impl ExecutionGadget for MemoryGadget { // Inputs/Outputs let [address, value] = [0, 1].map(|index| block.get_rws(step, index).stack_value()); - self.address.assign( - region, - offset, - Some(address.to_le_bytes()[..5].try_into().unwrap()), - )?; - self.value - .assign(region, offset, Some(value.to_le_bytes()))?; + self.address.assign_u256(region, offset, address)?; + self.value.assign_u256(region, offset, value)?; // Check if this is an MLOAD self.is_mload.assign( diff --git a/zkevm-circuits/src/evm_circuit/execution/msize.rs b/zkevm-circuits/src/evm_circuit/execution/msize.rs index 37d04e91fe..8e76cb8aa9 100644 --- a/zkevm-circuits/src/evm_circuit/execution/msize.rs +++ b/zkevm-circuits/src/evm_circuit/execution/msize.rs @@ -9,20 +9,20 @@ use crate::{ ConstrainBuilderCommon, EVMConstraintBuilder, StepStateTransition, Transition::Delta, }, - from_bytes, CachedRegion, RandomLinearCombination, + CachedRegion, Cell, }, witness::{Block, Call, ExecStep, Transaction}, }, - util::Expr, + util::{word::Word, Expr}, }; use bus_mapping::evm::OpcodeId; use eth_types::Field; -use halo2_proofs::plonk::Error; +use halo2_proofs::{circuit::Value, plonk::Error}; #[derive(Clone, Debug)] pub(crate) struct MsizeGadget { same_context: SameContextGadget, - value: RandomLinearCombination, + value: Cell, } impl ExecutionGadget for MsizeGadget { @@ -31,17 +31,18 @@ impl ExecutionGadget for MsizeGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::MSIZE; fn configure(cb: &mut EVMConstraintBuilder) -> Self { - let value = cb.query_word_rlc(); + let value = cb.query_cell(); - // memory_size is limited to 64 bits so we only consider 8 bytes + // memory_size is limited to 64 bits + // constrain equality with step state therefore only use single cell cb.require_equal( "Constrain memory_size equal to stack value", - from_bytes::expr(&value.cells), + value.expr(), cb.curr.state.memory_word_size.expr() * N_BYTES_WORD.expr(), ); // Push the value on the stack - cb.stack_push(value.expr()); + cb.stack_push_word(Word::from_lo_unchecked(value.expr())); // State transition let step_state_transition = StepStateTransition { @@ -70,8 +71,11 @@ impl ExecutionGadget for MsizeGadget { step: &ExecStep, ) -> Result<(), Error> { self.same_context.assign_exec_step(region, offset, step)?; - self.value - .assign(region, offset, Some((step.memory_size).to_le_bytes()))?; + self.value.assign( + region, + offset, + Value::known(F::from(step.memory_size as u64)), + )?; Ok(()) } 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 8804392410..2f11516200 100644 --- a/zkevm-circuits/src/evm_circuit/execution/mul_div_mod.rs +++ b/zkevm-circuits/src/evm_circuit/execution/mul_div_mod.rs @@ -3,21 +3,23 @@ use crate::{ execution::ExecutionGadget, step::ExecutionState, util::{ - self, common_gadget::SameContextGadget, constraint_builder::{ ConstrainBuilderCommon, EVMConstraintBuilder, StepStateTransition, Transition::Delta, }, - math_gadget::{IsZeroGadget, LtWordGadget, MulAddWordsGadget}, - select, sum, CachedRegion, + math_gadget::{IsZeroWordGadget, LtWordGadget, MulAddWordsGadget}, + CachedRegion, }, witness::{Block, Call, ExecStep, Transaction}, }, - util::Expr, + util::{ + word::{Word, Word32Cell, WordExpr}, + Expr, + }, }; use bus_mapping::evm::OpcodeId; -use eth_types::{Field, ToLittleEndian, U256}; +use eth_types::{Field, U256}; use halo2_proofs::plonk::Error; /// MulGadget verifies opcode MUL, DIV, and MOD. @@ -29,11 +31,11 @@ use halo2_proofs::plonk::Error; pub(crate) struct MulDivModGadget { same_context: SameContextGadget, /// Words a, b, c, d - pub words: [util::Word; 4], + pub words: [Word32Cell; 4], /// Gadget that verifies a * b + c = d mul_add_words: MulAddWordsGadget, /// Check if divisor is zero for DIV and MOD - divisor_is_zero: IsZeroGadget, + divisor_is_zero: IsZeroWordGadget>, /// Check if residue < divisor when divisor != 0 for DIV and MOD lt_word: LtWordGadget, } @@ -55,32 +57,39 @@ 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_rlc(); - let b = cb.query_word_rlc(); - let c = cb.query_word_rlc(); - let d = cb.query_word_rlc(); + let a = cb.query_word32(); + let b = cb.query_word32(); + let c = cb.query_word32(); + let d = cb.query_word32(); let mul_add_words = MulAddWordsGadget::construct(cb, [&a, &b, &c, &d]); - let divisor_is_zero = IsZeroGadget::construct(cb, sum::expr(&b.cells)); - let lt_word = LtWordGadget::construct(cb, &c, &b); + let divisor_is_zero = IsZeroWordGadget::construct(cb, &b); + let lt_word = LtWordGadget::construct(cb, &c.to_word(), &b.to_word()); // Pop a and b from the stack, push result on the stack // The first pop is multiplier for MUL and dividend for DIV/MOD // The second pop is multiplicand for MUL and divisor for DIV/MOD // The push is product for MUL, quotient for DIV, and residue for MOD // Note that for DIV/MOD, when divisor == 0, the push value is also 0. - cb.stack_pop(select::expr(is_mul.clone(), a.expr(), d.expr())); - cb.stack_pop(b.expr()); - cb.stack_push( - is_mul.clone() * d.expr() - + is_div * a.expr() * (1.expr() - divisor_is_zero.expr()) - + is_mod * c.expr() * (1.expr() - divisor_is_zero.expr()), + cb.stack_pop_word(Word::select(is_mul.clone(), a.to_word(), d.to_word())); + cb.stack_pop_word(b.to_word()); + cb.stack_push_word( + d.to_word() + .mul_selector(is_mul.clone()) + .add_unchecked( + a.to_word() + .mul_selector(is_div * (1.expr() - divisor_is_zero.expr())), + ) + .add_unchecked( + c.to_word() + .mul_selector(is_mod * (1.expr() - divisor_is_zero.expr())), + ), ); // Constraint for MUL case - cb.add_constraint( + cb.require_zero_word( "c == 0 for opcode MUL", - is_mul.clone() * sum::expr(&c.cells), + c.to_word().mul_selector(is_mul.clone()), ); // Constraints for DIV and MOD cases @@ -137,15 +146,13 @@ impl ExecutionGadget for MulDivModGadget { ), _ => unreachable!(), }; - self.words[0].assign(region, offset, Some(a.to_le_bytes()))?; - self.words[1].assign(region, offset, Some(b.to_le_bytes()))?; - self.words[2].assign(region, offset, Some(c.to_le_bytes()))?; - self.words[3].assign(region, offset, Some(d.to_le_bytes()))?; + self.words[0].assign_u256(region, offset, a)?; + self.words[1].assign_u256(region, offset, b)?; + self.words[2].assign_u256(region, offset, c)?; + self.words[3].assign_u256(region, offset, d)?; self.mul_add_words.assign(region, offset, [a, b, c, d])?; self.lt_word.assign(region, offset, c, b)?; - let b_sum = (0..32).fold(0, |acc, idx| acc + b.byte(idx) as u64); - self.divisor_is_zero - .assign(region, offset, F::from(b_sum))?; + self.divisor_is_zero.assign(region, offset, Word::from(b))?; Ok(()) } } diff --git a/zkevm-circuits/src/evm_circuit/execution/mulmod.rs b/zkevm-circuits/src/evm_circuit/execution/mulmod.rs index f6b1a9c4b2..5a091aac49 100644 --- a/zkevm-circuits/src/evm_circuit/execution/mulmod.rs +++ b/zkevm-circuits/src/evm_circuit/execution/mulmod.rs @@ -8,15 +8,18 @@ use crate::{ ConstrainBuilderCommon, EVMConstraintBuilder, StepStateTransition, Transition::Delta, }, - math_gadget::{IsZeroGadget, LtWordGadget, ModGadget, MulAddWords512Gadget}, - sum, CachedRegion, Word, + math_gadget::{IsZeroWordGadget, LtWordGadget, ModGadget, MulAddWords512Gadget}, + CachedRegion, }, witness::{Block, Call, ExecStep, Transaction}, }, - util::Expr, + util::{ + word::{Word, Word32Cell, WordExpr}, + Expr, + }, }; use bus_mapping::evm::OpcodeId; -use eth_types::{Field, ToLittleEndian, U256}; +use eth_types::{Field, U256}; use halo2_proofs::plonk::Error; /// MulModGadget verifies opcode MULMOD @@ -26,15 +29,15 @@ use halo2_proofs::plonk::Error; pub(crate) struct MulModGadget { same_context: SameContextGadget, // a, b, n, r - pub words: [Word; 4], - k: Word, - a_reduced: Word, - d: Word, - e: Word, + pub words: [Word32Cell; 4], + k: Word32Cell, + a_reduced: Word32Cell, + d: Word32Cell, + e: Word32Cell, modword: ModGadget, mul512_left: MulAddWords512Gadget, mul512_right: MulAddWords512Gadget, - n_is_zero: IsZeroGadget, + n_is_zero: IsZeroWordGadget>, lt: LtWordGadget, } @@ -46,39 +49,38 @@ impl ExecutionGadget for MulModGadget { fn configure(cb: &mut EVMConstraintBuilder) -> Self { let opcode = cb.query_cell(); - 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 a = cb.query_word32(); + let b = cb.query_word32(); + let n = cb.query_word32(); + let r = cb.query_word32(); - let k = cb.query_word_rlc(); + let k = cb.query_word32(); - let a_reduced = cb.query_word_rlc(); - let d = cb.query_word_rlc(); - let e = cb.query_word_rlc(); + let a_reduced = cb.query_word32(); + let d = cb.query_word32(); + let e = cb.query_word32(); // 1. k1 * n + a_reduced == a let modword = ModGadget::construct(cb, [&a, &n, &a_reduced]); // 2. a_reduced * b + 0 == d * 2^256 + e - let mul512_left = - MulAddWords512Gadget::legacy_construct(cb, [&a_reduced, &b, &d, &e], None); + let mul512_left = MulAddWords512Gadget::construct(cb, [&a_reduced, &b, &d, &e], None); // 3. k2 * n + r == d * 2^256 + e - let mul512_right = MulAddWords512Gadget::legacy_construct(cb, [&k, &n, &d, &e], Some(&r)); + let mul512_right = MulAddWords512Gadget::construct(cb, [&k, &n, &d, &e], Some(&r)); // (r < n ) or n == 0 - let n_is_zero = IsZeroGadget::construct(cb, sum::expr(&n.cells)); - let lt = LtWordGadget::construct(cb, &r, &n); + let n_is_zero = IsZeroWordGadget::construct(cb, &n); + let lt = LtWordGadget::construct(cb, &r.to_word(), &n.to_word()); cb.add_constraint( " (1 - (r < n) - (n==0)) ", 1.expr() - lt.expr() - n_is_zero.expr(), ); - cb.stack_pop(a.expr()); - cb.stack_pop(b.expr()); - cb.stack_pop(n.expr()); - cb.stack_push(r.expr()); + cb.stack_pop_word(a.to_word()); + cb.stack_pop_word(b.to_word()); + cb.stack_pop_word(n.to_word()); + cb.stack_push_word(r.to_word()); // State transition let step_state_transition = StepStateTransition { @@ -117,10 +119,10 @@ impl ExecutionGadget for MulModGadget { self.same_context.assign_exec_step(region, offset, step)?; let [r, n, b, a] = [3, 2, 1, 0].map(|index| block.get_rws(step, index).stack_value()); - self.words[0].assign(region, offset, Some(a.to_le_bytes()))?; - self.words[1].assign(region, offset, Some(b.to_le_bytes()))?; - self.words[2].assign(region, offset, Some(n.to_le_bytes()))?; - self.words[3].assign(region, offset, Some(r.to_le_bytes()))?; + self.words[0].assign_u256(region, offset, a)?; + self.words[1].assign_u256(region, offset, b)?; + self.words[2].assign_u256(region, offset, n)?; + self.words[3].assign_u256(region, offset, r)?; // 1. quotient and reduction of a mod n let (k1, a_reduced) = if n.is_zero() { (U256::zero(), U256::zero()) @@ -142,11 +144,10 @@ impl ExecutionGadget for MulModGadget { (r, U256::try_from(prod / n).unwrap()) }; - self.k.assign(region, offset, Some(k2.to_le_bytes()))?; - self.a_reduced - .assign(region, offset, Some(a_reduced.to_le_bytes()))?; - self.d.assign(region, offset, Some(d.to_le_bytes()))?; - self.e.assign(region, offset, Some(e.to_le_bytes()))?; + self.k.assign_u256(region, offset, k2)?; + self.a_reduced.assign_u256(region, offset, a_reduced)?; + self.d.assign_u256(region, offset, d)?; + self.e.assign_u256(region, offset, e)?; self.modword.assign(region, offset, a, n, a_reduced, k1)?; self.mul512_left @@ -156,8 +157,7 @@ impl ExecutionGadget for MulModGadget { self.lt.assign(region, offset, r, n)?; - let n_sum = (0..32).fold(0, |acc, idx| acc + n.byte(idx) as u64); - self.n_is_zero.assign(region, offset, F::from(n_sum))?; + self.n_is_zero.assign(region, offset, Word::from(n))?; Ok(()) } } diff --git a/zkevm-circuits/src/evm_circuit/execution/not.rs b/zkevm-circuits/src/evm_circuit/execution/not.rs index 37ddcc3f1b..398272d83d 100644 --- a/zkevm-circuits/src/evm_circuit/execution/not.rs +++ b/zkevm-circuits/src/evm_circuit/execution/not.rs @@ -6,20 +6,23 @@ use crate::{ util::{ common_gadget::SameContextGadget, constraint_builder::{EVMConstraintBuilder, StepStateTransition, Transition::Delta}, - CachedRegion, Word, + CachedRegion, }, witness::{Block, Call, ExecStep, Transaction}, }, - util::Expr, + util::{ + word::{Word32Cell, WordExpr}, + Expr, + }, }; -use eth_types::{evm_types::OpcodeId, Field, ToLittleEndian}; +use eth_types::{evm_types::OpcodeId, Field}; use halo2_proofs::plonk::Error; #[derive(Clone, Debug)] pub(crate) struct NotGadget { same_context: SameContextGadget, - input: Word, - output: Word, + input: Word32Cell, + output: Word32Cell, } impl ExecutionGadget for NotGadget { @@ -30,13 +33,13 @@ impl ExecutionGadget for NotGadget { fn configure(cb: &mut EVMConstraintBuilder) -> Self { let opcode = cb.query_cell(); - let input = cb.query_word_rlc(); - let output = cb.query_word_rlc(); + let input = cb.query_word32(); + let output = cb.query_word32(); - cb.stack_pop(input.expr()); - cb.stack_push(output.expr()); + cb.stack_pop_word(input.to_word()); + cb.stack_push_word(output.to_word()); - for (i, o) in input.cells.iter().zip(output.cells.iter()) { + for (i, o) in input.limbs.iter().zip(output.limbs.iter()) { cb.add_lookup( "input XOR output is all 1's", Lookup::Fixed { @@ -75,10 +78,8 @@ impl ExecutionGadget for NotGadget { self.same_context.assign_exec_step(region, offset, step)?; let [input, output] = [0, 1].map(|index| block.get_rws(step, index).stack_value()); - self.input - .assign(region, offset, Some(input.to_le_bytes()))?; - self.output - .assign(region, offset, Some(output.to_le_bytes()))?; + self.input.assign_u256(region, offset, input)?; + self.output.assign_u256(region, offset, output)?; Ok(()) } diff --git a/zkevm-circuits/src/evm_circuit/execution/origin.rs b/zkevm-circuits/src/evm_circuit/execution/origin.rs index f53d0e2099..27f201fabf 100644 --- a/zkevm-circuits/src/evm_circuit/execution/origin.rs +++ b/zkevm-circuits/src/evm_circuit/execution/origin.rs @@ -1,26 +1,25 @@ use crate::{ evm_circuit::{ execution::ExecutionGadget, - param::N_BYTES_ACCOUNT_ADDRESS, step::ExecutionState, util::{ common_gadget::SameContextGadget, constraint_builder::{EVMConstraintBuilder, StepStateTransition, Transition::Delta}, - from_bytes, CachedRegion, Cell, RandomLinearCombination, + AccountAddress, CachedRegion, Cell, }, witness::{Block, Call, ExecStep, Transaction}, }, table::{CallContextFieldTag, TxContextFieldTag}, - util::Expr, + util::{word::WordExpr, 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)] pub(crate) struct OriginGadget { tx_id: Cell, - origin: RandomLinearCombination, + origin: AccountAddress, same_context: SameContextGadget, } @@ -30,20 +29,20 @@ impl ExecutionGadget for OriginGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::ORIGIN; fn configure(cb: &mut EVMConstraintBuilder) -> Self { - let origin = cb.query_word_rlc::(); + let origin = cb.query_account_address(); // Lookup in call_ctx the TxId let tx_id = cb.call_context(None, CallContextFieldTag::TxId); // Lookup rw_table -> call_context with tx origin address - cb.tx_context_lookup( + cb.tx_context_lookup_word( tx_id.expr(), TxContextFieldTag::CallerAddress, None, // None because unrelated to calldata - from_bytes::expr(&origin.cells), + origin.to_word(), ); // Push the value to the stack - cb.stack_push(origin.expr()); + cb.stack_push_word(origin.to_word()); // State transition let opcode = cb.query_cell(); @@ -78,16 +77,8 @@ impl ExecutionGadget for OriginGadget { self.tx_id .assign(region, offset, Value::known(F::from(tx.id as u64)))?; - // Assign Origin addr RLC. - self.origin.assign( - region, - offset, - Some( - origin.to_le_bytes()[..N_BYTES_ACCOUNT_ADDRESS] - .try_into() - .unwrap(), - ), - )?; + // Assign Origin addr. + self.origin.assign_u256(region, offset, origin)?; // Assign SameContextGadget witnesses. self.same_context.assign_exec_step(region, offset, step)?; diff --git a/zkevm-circuits/src/evm_circuit/execution/pc.rs b/zkevm-circuits/src/evm_circuit/execution/pc.rs index 905ae21d5c..927aadd745 100644 --- a/zkevm-circuits/src/evm_circuit/execution/pc.rs +++ b/zkevm-circuits/src/evm_circuit/execution/pc.rs @@ -1,7 +1,6 @@ use crate::{ evm_circuit::{ execution::ExecutionGadget, - param::N_BYTES_PROGRAM_COUNTER, step::ExecutionState, util::{ common_gadget::SameContextGadget, @@ -9,11 +8,11 @@ use crate::{ ConstrainBuilderCommon, EVMConstraintBuilder, StepStateTransition, Transition::Delta, }, - from_bytes, CachedRegion, RandomLinearCombination, + CachedRegion, U64Cell, }, witness::{Block, Call, ExecStep, Transaction}, }, - util::Expr, + util::{word::WordExpr, Expr}, }; use bus_mapping::evm::OpcodeId; use eth_types::Field; @@ -22,7 +21,7 @@ use halo2_proofs::plonk::Error; #[derive(Clone, Debug)] pub(crate) struct PcGadget { same_context: SameContextGadget, - value: RandomLinearCombination, + value: U64Cell, } impl ExecutionGadget for PcGadget { @@ -31,17 +30,17 @@ impl ExecutionGadget for PcGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::PC; fn configure(cb: &mut EVMConstraintBuilder) -> Self { - let value = cb.query_word_rlc(); + let value = cb.query_u64(); // program_counter is limited to 64 bits so we only consider 8 bytes cb.require_equal( "Constrain program_counter equal to stack value", - from_bytes::expr(&value.cells), + value.expr(), cb.curr.state.program_counter.expr(), ); // Push the value on the stack - cb.stack_push(value.expr()); + cb.stack_push_word(value.to_word()); // State transition let step_state_transition = StepStateTransition { diff --git a/zkevm-circuits/src/evm_circuit/execution/pop.rs b/zkevm-circuits/src/evm_circuit/execution/pop.rs index 93103a4ae3..0914c107eb 100644 --- a/zkevm-circuits/src/evm_circuit/execution/pop.rs +++ b/zkevm-circuits/src/evm_circuit/execution/pop.rs @@ -5,11 +5,14 @@ use crate::{ util::{ common_gadget::SameContextGadget, constraint_builder::{EVMConstraintBuilder, StepStateTransition, Transition::Delta}, - CachedRegion, Cell, + CachedRegion, }, witness::{Block, Call, ExecStep, Transaction}, }, - util::Expr, + util::{ + word::{WordCell, WordExpr}, + Expr, + }, }; use bus_mapping::evm::OpcodeId; use eth_types::Field; @@ -18,7 +21,7 @@ use halo2_proofs::plonk::Error; #[derive(Clone, Debug)] pub(crate) struct PopGadget { same_context: SameContextGadget, - phase2_value: Cell, + value: WordCell, } impl ExecutionGadget for PopGadget { @@ -27,10 +30,10 @@ impl ExecutionGadget for PopGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::POP; fn configure(cb: &mut EVMConstraintBuilder) -> Self { - let phase2_value = cb.query_cell_phase2(); + let value = cb.query_word_unchecked(); // Pop the value from the stack - cb.stack_pop(phase2_value.expr()); + cb.stack_pop_word(value.to_word()); // State transition let step_state_transition = StepStateTransition { @@ -45,7 +48,7 @@ impl ExecutionGadget for PopGadget { Self { same_context, - phase2_value, + value, } } @@ -61,8 +64,7 @@ impl ExecutionGadget for PopGadget { self.same_context.assign_exec_step(region, offset, step)?; let value = block.get_rws(step, 0).stack_value(); - self.phase2_value - .assign(region, offset, region.word_rlc(value))?; + self.value.assign_u256(region, offset, value)?; Ok(()) } diff --git a/zkevm-circuits/src/evm_circuit/execution/push.rs b/zkevm-circuits/src/evm_circuit/execution/push.rs index bc9f9cd7dc..c6b88713c0 100644 --- a/zkevm-circuits/src/evm_circuit/execution/push.rs +++ b/zkevm-circuits/src/evm_circuit/execution/push.rs @@ -18,7 +18,7 @@ use crate::{ }, }; use array_init::array_init; -use eth_types::{evm_types::OpcodeId, Field, ToLittleEndian}; +use eth_types::{evm_types::OpcodeId, Field}; use halo2_proofs::{circuit::Value, plonk::Error}; #[derive(Clone, Debug)] @@ -132,8 +132,7 @@ impl ExecutionGadget for PushGadget { let opcode = step.opcode().unwrap(); let value = block.get_rws(step, 0).stack_value(); - self.value - .assign(region, offset, Some(value.to_le_bytes()))?; + self.value.assign_u256(region, offset, value)?; let num_additional_pushed = opcode.postfix().expect("opcode with postfix") - 1; for (idx, selector) in self.selectors.iter().enumerate() { diff --git a/zkevm-circuits/src/evm_circuit/execution/return_revert.rs b/zkevm-circuits/src/evm_circuit/execution/return_revert.rs index 9f1c0eeed2..48af306e0d 100644 --- a/zkevm-circuits/src/evm_circuit/execution/return_revert.rs +++ b/zkevm-circuits/src/evm_circuit/execution/return_revert.rs @@ -16,7 +16,10 @@ use crate::{ witness::{Block, Call, ExecStep, Transaction}, }, table::{AccountFieldTag, CallContextFieldTag}, - util::Expr, + util::{ + word::{Word, Word32Cell, WordCell, WordExpr}, + Expr, + }, }; use bus_mapping::{circuit_input_builder::CopyDataType, evm::OpcodeId, state_db::CodeDB}; use eth_types::{evm_types::GasCost, Field, ToScalar, U256}; @@ -40,10 +43,10 @@ pub(crate) struct ReturnRevertGadget { return_data_length: Cell, memory_expansion: MemoryExpansionGadget, - code_hash: Cell, + code_hash: Word32Cell, caller_id: Cell, - address: Cell, + address: WordCell, reversion_info: ReversionInfo, } @@ -56,10 +59,10 @@ impl ExecutionGadget for ReturnRevertGadget { let opcode = cb.query_cell(); cb.opcode_lookup(opcode.expr(), 1.expr()); - let offset = cb.query_cell_phase2(); - let length = cb.query_word_rlc(); - cb.stack_pop(offset.expr()); - cb.stack_pop(length.expr()); + let offset = cb.query_word_unchecked(); + let length = cb.query_memory_address(); + cb.stack_pop_word(offset.to_word()); + cb.stack_pop_word(length.to_word()); let range = MemoryAddressGadget::construct(cb, offset, length); let is_success = cb.call_context(None, CallContextFieldTag::IsSuccess); @@ -102,12 +105,12 @@ impl ExecutionGadget for ReturnRevertGadget { cb.condition(is_contract_deployment.clone(), |cb| { // We don't need to place any additional constraints on code_hash because the // copy circuit enforces that it is the hash of the bytes in the copy lookup. - let code_hash = cb.query_cell_phase2(); + let code_hash = cb.query_word32(); let deployed_code_rlc = cb.query_cell_phase2(); cb.copy_table_lookup( - cb.curr.state.call_id.expr(), + Word::from_lo_unchecked(cb.curr.state.call_id.expr()), CopyDataType::Memory.expr(), - code_hash.expr(), + code_hash.to_word(), CopyDataType::Bytecode.expr(), range.offset(), range.address(), @@ -117,18 +120,17 @@ impl ExecutionGadget for ReturnRevertGadget { copy_rw_increase.expr(), ); - let [caller_id, address] = [ - CallContextFieldTag::CallerId, - CallContextFieldTag::CalleeAddress, - ] - .map(|tag| cb.call_context(None, tag)); + let caller_id = cb.call_context(None, CallContextFieldTag::CallerId); + let address = + cb.call_context_read_as_word(None, CallContextFieldTag::CalleeAddress); + let mut reversion_info = cb.reversion_info_read(None); - cb.account_write( - address.expr(), + cb.account_write_word( + address.to_word(), AccountFieldTag::CodeHash, - code_hash.expr(), - cb.empty_code_hash_rlc(), + code_hash.to_word(), + cb.empty_code_hash_word(), Some(&mut reversion_info), ); @@ -144,11 +146,10 @@ impl ExecutionGadget for ReturnRevertGadget { // Case B in the specs. cb.condition(is_root.expr(), |cb| { cb.require_next_state(ExecutionState::EndTx); - cb.call_context_lookup( - false.expr(), + cb.call_context_lookup_read( None, CallContextFieldTag::IsPersistent, - is_success.expr(), + Word::from_lo_unchecked(is_success.expr()), ); cb.require_step_state_transition(StepStateTransition { program_counter: To(0.expr()), @@ -203,9 +204,9 @@ impl ExecutionGadget for ReturnRevertGadget { * not::expr(copy_rw_increase_is_zero.expr()), |cb| { cb.copy_table_lookup( - cb.curr.state.call_id.expr(), + Word::from_lo_unchecked(cb.curr.state.call_id.expr()), CopyDataType::Memory.expr(), - cb.next.state.call_id.expr(), + Word::from_lo_unchecked(cb.next.state.call_id.expr()), CopyDataType::Memory.expr(), range.offset(), range.address(), @@ -298,11 +299,8 @@ impl ExecutionGadget for ReturnRevertGadget { )?; let mut code_hash = CodeDB::hash(&values).to_fixed_bytes(); code_hash.reverse(); - self.code_hash.assign( - region, - offset, - region.word_rlc(U256::from_little_endian(&code_hash)), - )?; + self.code_hash + .assign_u256(region, offset, U256::from_little_endian(&code_hash))?; } let copy_rw_increase = if call.is_create() && call.is_success { @@ -340,11 +338,7 @@ impl ExecutionGadget for ReturnRevertGadget { Value::known(call.caller_id.to_scalar().unwrap()), )?; - self.address.assign( - region, - offset, - Value::known(call.address.to_scalar().unwrap()), - )?; + self.address.assign_h160(region, offset, call.address)?; self.reversion_info.assign( region, diff --git a/zkevm-circuits/src/evm_circuit/execution/returndatacopy.rs b/zkevm-circuits/src/evm_circuit/execution/returndatacopy.rs index aed699e68a..6bda0ef570 100644 --- a/zkevm-circuits/src/evm_circuit/execution/returndatacopy.rs +++ b/zkevm-circuits/src/evm_circuit/execution/returndatacopy.rs @@ -1,7 +1,7 @@ use crate::{ evm_circuit::{ execution::ExecutionGadget, - param::{N_BYTES_MEMORY_ADDRESS, N_BYTES_MEMORY_WORD_SIZE}, + param::N_BYTES_MEMORY_WORD_SIZE, step::ExecutionState, util::{ common_gadget::SameContextGadget, @@ -9,7 +9,6 @@ use crate::{ ConstrainBuilderCommon, EVMConstraintBuilder, StepStateTransition, Transition::{Delta, To}, }, - from_bytes, math_gadget::RangeCheckGadget, memory_gadget::{MemoryAddressGadget, MemoryCopierGasGadget, MemoryExpansionGadget}, CachedRegion, Cell, MemoryAddress, @@ -17,10 +16,13 @@ use crate::{ witness::{Block, Call, ExecStep, Transaction}, }, table::CallContextFieldTag, - util::Expr, + util::{ + word::{Word, WordExpr}, + Expr, + }, }; use bus_mapping::{circuit_input_builder::CopyDataType, evm::OpcodeId}; -use eth_types::{evm_types::GasCost, Field, ToLittleEndian, ToScalar}; +use eth_types::{evm_types::GasCost, Field, ToScalar}; use gadgets::util::not; use halo2_proofs::{circuit::Value, plonk::Error}; @@ -60,44 +62,40 @@ impl ExecutionGadget for ReturnDataCopyGadget { fn configure(cb: &mut EVMConstraintBuilder) -> Self { let opcode = cb.query_cell(); - let dest_offset = cb.query_cell_phase2(); - let data_offset = cb.query_word_rlc(); - let size = cb.query_word_rlc(); + let dest_offset = cb.query_word_unchecked(); + let data_offset = cb.query_memory_address(); + let size = cb.query_memory_address(); // 1. Pop dest_offset, offset, length from stack - cb.stack_pop(dest_offset.expr()); - cb.stack_pop(data_offset.expr()); - cb.stack_pop(size.expr()); + cb.stack_pop_word(dest_offset.to_word()); + cb.stack_pop_word(Word::from_lo_unchecked(data_offset.expr())); + cb.stack_pop_word(Word::from_lo_unchecked(size.expr())); // 2. Add lookup constraint in the call context for the returndatacopy field. let last_callee_id = cb.query_cell(); let return_data_offset = cb.query_cell(); let return_data_size = cb.query_cell(); - cb.call_context_lookup( - false.expr(), + cb.call_context_lookup_read( None, CallContextFieldTag::LastCalleeId, - last_callee_id.expr(), + Word::from_lo_unchecked(last_callee_id.expr()), ); - cb.call_context_lookup( - false.expr(), + cb.call_context_lookup_read( None, CallContextFieldTag::LastCalleeReturnDataOffset, - return_data_offset.expr(), + Word::from_lo_unchecked(return_data_offset.expr()), ); - cb.call_context_lookup( - false.expr(), + cb.call_context_lookup_read( None, CallContextFieldTag::LastCalleeReturnDataLength, - return_data_size.expr(), + Word::from_lo_unchecked(return_data_size.expr()), ); // 3. contraints for copy: copy overflow check // i.e., offset + size <= return_data_size let in_bound_check = RangeCheckGadget::construct( cb, - return_data_size.expr() - - (from_bytes::expr(&data_offset.cells) + from_bytes::expr(&size.cells)), + return_data_size.expr() - (data_offset.expr() + size.expr()), ); // 4. memory copy @@ -117,11 +115,11 @@ impl ExecutionGadget for ReturnDataCopyGadget { let copy_rwc_inc = cb.query_cell(); cb.condition(dst_memory_addr.has_length(), |cb| { cb.copy_table_lookup( - last_callee_id.expr(), + Word::from_lo_unchecked(last_callee_id.expr()), CopyDataType::Memory.expr(), - cb.curr.state.call_id.expr(), + Word::from_lo_unchecked(cb.curr.state.call_id.expr()), CopyDataType::Memory.expr(), - return_data_offset.expr() + from_bytes::expr(&data_offset.cells), + return_data_offset.expr() + data_offset.expr(), return_data_offset.expr() + return_data_size.expr(), dst_memory_addr.offset(), dst_memory_addr.length(), @@ -178,15 +176,7 @@ impl ExecutionGadget for ReturnDataCopyGadget { let [dest_offset, data_offset, size] = [0, 1, 2].map(|index| block.get_rws(step, index).stack_value()); - self.data_offset.assign( - region, - offset, - Some( - data_offset.to_le_bytes()[..N_BYTES_MEMORY_ADDRESS] - .try_into() - .unwrap(), - ), - )?; + self.data_offset.assign_u256(region, offset, data_offset)?; let [last_callee_id, return_data_offset, return_data_size] = [ (3, CallContextFieldTag::LastCalleeId), diff --git a/zkevm-circuits/src/evm_circuit/execution/returndatasize.rs b/zkevm-circuits/src/evm_circuit/execution/returndatasize.rs index 60aaafa0f0..96bba3753b 100644 --- a/zkevm-circuits/src/evm_circuit/execution/returndatasize.rs +++ b/zkevm-circuits/src/evm_circuit/execution/returndatasize.rs @@ -1,26 +1,28 @@ use crate::{ evm_circuit::{ execution::ExecutionGadget, - param::N_BYTES_U64, step::ExecutionState, util::{ common_gadget::SameContextGadget, constraint_builder::{EVMConstraintBuilder, StepStateTransition, Transition::Delta}, - from_bytes, CachedRegion, RandomLinearCombination, + CachedRegion, }, witness::{Block, Call, ExecStep, Transaction}, }, table::CallContextFieldTag, - util::Expr, + util::{ + word::{WordCell, WordExpr}, + Expr, + }, }; use bus_mapping::evm::OpcodeId; -use eth_types::{Field, ToLittleEndian}; +use eth_types::Field; use halo2_proofs::plonk::Error; #[derive(Clone, Debug)] pub(crate) struct ReturnDataSizeGadget { same_context: SameContextGadget, - return_data_size: RandomLinearCombination, + return_data_size: WordCell, } impl ExecutionGadget for ReturnDataSizeGadget { @@ -32,16 +34,15 @@ 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_word_rlc(); - cb.call_context_lookup( - false.expr(), + let return_data_size = cb.query_word_unchecked(); + cb.call_context_lookup_read( None, CallContextFieldTag::LastCalleeReturnDataLength, - from_bytes::expr(&return_data_size.cells), + return_data_size.to_word(), ); // The returndatasize should be pushed to the top of the stack. - cb.stack_push(return_data_size.expr()); + cb.stack_push_word(return_data_size.to_word()); let step_state_transition = StepStateTransition { rw_counter: Delta(2.expr()), @@ -70,15 +71,8 @@ impl ExecutionGadget for ReturnDataSizeGadget { ) -> Result<(), Error> { self.same_context.assign_exec_step(region, offset, step)?; let return_data_size = block.get_rws(step, 1).stack_value(); - self.return_data_size.assign( - region, - offset, - Some( - return_data_size.to_le_bytes()[..N_BYTES_U64] - .try_into() - .expect("could not encode return_data_size as byte array in little endian"), - ), - )?; + self.return_data_size + .assign_u64(region, offset, return_data_size.as_u64())?; Ok(()) } diff --git a/zkevm-circuits/src/evm_circuit/execution/sar.rs b/zkevm-circuits/src/evm_circuit/execution/sar.rs index 87dbd318a5..bf68e4d0ef 100644 --- a/zkevm-circuits/src/evm_circuit/execution/sar.rs +++ b/zkevm-circuits/src/evm_circuit/execution/sar.rs @@ -1,7 +1,6 @@ use crate::{ evm_circuit::{ execution::ExecutionGadget, - param::N_BYTES_U64, step::ExecutionState, table::{FixedTableTag, Lookup}, util::{ @@ -10,18 +9,23 @@ use crate::{ ConstrainBuilderCommon, EVMConstraintBuilder, StepStateTransition, Transition::Delta, }, - from_bytes, math_gadget::{IsEqualGadget, IsZeroGadget, LtGadget}, - select, sum, CachedRegion, Cell, Word, + select, sum, CachedRegion, Cell, }, witness::{Block, Call, ExecStep, Transaction}, }, - util::Expr, + util::{ + word::{Word32Cell, Word4, WordExpr}, + Expr, + }, }; 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}, +}; /// SarGadget verifies SAR opcode. /// Verify signed word shift right as `signed(a) >> shift == signed(b)`; @@ -29,9 +33,9 @@ use halo2_proofs::{circuit::Value, plonk::Error}; #[derive(Clone, Debug)] pub(crate) struct SarGadget { same_context: SameContextGadget, - shift: Word, - a: Word, - b: Word, + shift: Word32Cell, + a: Word32Cell, + b: Word32Cell, // Each of the four `a64s` limbs is split into two parts (`a64s_lo` and `a64s_hi`) at position // `shf_mod64`, `a64s_lo` is the lower `shf_mod64` bits. a64s_lo: [Cell; 4], @@ -77,13 +81,16 @@ impl ExecutionGadget for SarGadget { fn configure(cb: &mut EVMConstraintBuilder) -> Self { let opcode = cb.query_cell(); - let shift = cb.query_word_rlc(); - let a = cb.query_word_rlc(); - let b = cb.query_word_rlc(); + let shift = cb.query_word32(); + let a = cb.query_word32(); + let b = cb.query_word32(); + + cb.stack_pop_word(shift.to_word()); + cb.stack_pop_word(a.to_word()); + cb.stack_push_word(b.to_word()); - cb.stack_pop(shift.expr()); - cb.stack_pop(a.expr()); - cb.stack_push(b.expr()); + let a64s: Word4> = a.to_word_n(); + let b64s: Word4> = b.to_word_n(); let a64s_lo = array_init(|_| cb.query_cell()); let a64s_hi = array_init(|_| cb.query_cell()); @@ -92,13 +99,13 @@ impl ExecutionGadget for SarGadget { let p_lo = cb.query_cell(); let p_hi = cb.query_cell(); let p_top = cb.query_cell(); - let is_neg = LtGadget::construct(cb, 127.expr(), a.cells[31].expr()); - let shf_lt256 = IsZeroGadget::construct(cb, sum::expr(&shift.cells[1..32])); + let is_neg = LtGadget::construct(cb, 127.expr(), a.limbs[31].expr()); + let shf_lt256 = IsZeroGadget::construct(cb, sum::expr(&shift.limbs[1..32])); for idx in 0..4 { cb.require_equal( "a64s[idx] == a64s_lo[idx] + a64s_hi[idx] * p_lo", - from_bytes::expr(&a.cells[N_BYTES_U64 * idx..N_BYTES_U64 * (idx + 1)]), + a64s.limbs[idx].clone(), a64s_lo[idx].expr() + a64s_hi[idx].expr() * p_lo.expr(), ); } @@ -129,7 +136,7 @@ impl ExecutionGadget for SarGadget { cb.require_equal( "Constrain merged b64s[0] value", - from_bytes::expr(&b.cells[0..N_BYTES_U64]), + b64s.limbs[0].expr(), (a64s_hi[0].expr() + a64s_lo[1].expr() * p_hi.expr()) * shf_div64_eq0.expr() + (a64s_hi[1].expr() + a64s_lo[2].expr() * p_hi.expr()) * shf_div64_eq1.expr() + (a64s_hi[2].expr() + a64s_lo[3].expr() * p_hi.expr()) * shf_div64_eq2.expr() @@ -144,7 +151,7 @@ impl ExecutionGadget for SarGadget { ); cb.require_equal( "Constrain merged b64s[1] value", - from_bytes::expr(&b.cells[N_BYTES_U64..N_BYTES_U64 * 2]), + b64s.limbs[1].expr(), (a64s_hi[1].expr() + a64s_lo[2].expr() * p_hi.expr()) * shf_div64_eq0.expr() + (a64s_hi[2].expr() + a64s_lo[3].expr() * p_hi.expr()) * shf_div64_eq1.expr() + (a64s_hi[3].expr() + p_top.expr()) * shf_div64_eq2.expr() @@ -157,7 +164,7 @@ impl ExecutionGadget for SarGadget { ); cb.require_equal( "Constrain merged b64s[2] value", - from_bytes::expr(&b.cells[N_BYTES_U64 * 2..N_BYTES_U64 * 3]), + b64s.limbs[2].expr(), (a64s_hi[2].expr() + a64s_lo[3].expr() * p_hi.expr()) * shf_div64_eq0.expr() + (a64s_hi[3].expr() + p_top.expr()) * shf_div64_eq1.expr() + is_neg.expr() @@ -166,7 +173,7 @@ impl ExecutionGadget for SarGadget { ); cb.require_equal( "Constrain merged b64s[3] value", - from_bytes::expr(&b.cells[N_BYTES_U64 * 3..]), + b64s.limbs[3].expr(), (a64s_hi[3].expr() + p_top.expr()) * shf_div64_eq0.expr() + is_neg.expr() * u64::MAX.expr() * (1.expr() - shf_div64_eq0.expr()), ); @@ -178,7 +185,7 @@ impl ExecutionGadget for SarGadget { cb.require_equal("shf_mod64 < 64", shf_mod64_lt_64.expr(), 1.expr()); cb.require_equal( "shift[0] == shf_mod64 + shf_div64 * 64", - shift.cells[0].expr(), + shift.limbs[0].expr(), shf_mod64.expr() + shf_div64.expr() * 64.expr(), ); @@ -189,7 +196,7 @@ impl ExecutionGadget for SarGadget { Lookup::Fixed { tag: FixedTableTag::SignByte.expr(), values: [ - a.cells[31].expr(), + a.limbs[31].expr(), select::expr(is_neg.expr(), 255.expr(), 0.expr()), 0.expr(), ], @@ -268,10 +275,9 @@ impl ExecutionGadget for SarGadget { self.same_context.assign_exec_step(region, offset, step)?; let [shift, a, b] = [0, 1, 2].map(|idx| block.get_rws(step, idx).stack_value()); - self.shift - .assign(region, offset, Some(shift.to_le_bytes()))?; - self.a.assign(region, offset, Some(a.to_le_bytes()))?; - self.b.assign(region, offset, Some(b.to_le_bytes()))?; + self.shift.assign_u256(region, offset, shift)?; + self.a.assign_u256(region, offset, a)?; + self.b.assign_u256(region, offset, b)?; let is_neg = 127 < a.to_le_bytes()[31]; let shf0 = u128::from(shift.to_le_bytes()[0]); diff --git a/zkevm-circuits/src/evm_circuit/execution/sdiv_smod.rs b/zkevm-circuits/src/evm_circuit/execution/sdiv_smod.rs index 7398ced5ed..84bf7d4756 100644 --- a/zkevm-circuits/src/evm_circuit/execution/sdiv_smod.rs +++ b/zkevm-circuits/src/evm_circuit/execution/sdiv_smod.rs @@ -8,12 +8,17 @@ use crate::{ ConstrainBuilderCommon, EVMConstraintBuilder, StepStateTransition, Transition::Delta, }, - math_gadget::{AbsWordGadget, IsZeroGadget, LtGadget, LtWordGadget, MulAddWordsGadget}, - select, sum, CachedRegion, + math_gadget::{ + AbsWordGadget, IsZeroWordGadget, LtGadget, LtWordGadget, MulAddWordsGadget, + }, + CachedRegion, }, witness::{Block, Call, ExecStep, Transaction}, }, - util::Expr, + util::{ + word::{Word, Word32Cell, WordExpr}, + Expr, + }, }; use bus_mapping::evm::OpcodeId; use eth_types::{Field, ToLittleEndian, U256}; @@ -29,9 +34,9 @@ pub(crate) struct SignedDivModGadget { mul_add_words: MulAddWordsGadget, remainder_abs_lt_divisor_abs: LtWordGadget, dividend_is_signed_overflow: LtGadget, - quotient_is_zero: IsZeroGadget, - divisor_is_zero: IsZeroGadget, - remainder_is_zero: IsZeroGadget, + quotient_is_zero: IsZeroWordGadget>, + divisor_is_zero: IsZeroWordGadget>, + remainder_is_zero: IsZeroWordGadget>, } impl ExecutionGadget for SignedDivModGadget { @@ -47,33 +52,41 @@ impl ExecutionGadget for SignedDivModGadget { let divisor_abs_word = AbsWordGadget::construct(cb); let remainder_abs_word = AbsWordGadget::construct(cb); let dividend_abs_word = AbsWordGadget::construct(cb); - let quotient_is_zero = IsZeroGadget::construct(cb, sum::expr("ient_abs_word.x().cells)); - let divisor_is_zero = IsZeroGadget::construct(cb, sum::expr(&divisor_abs_word.x().cells)); - let remainder_is_zero = - IsZeroGadget::construct(cb, sum::expr(&remainder_abs_word.x().cells)); + let quotient_is_zero = IsZeroWordGadget::construct(cb, quotient_abs_word.x_word()); + let divisor_is_zero = IsZeroWordGadget::construct(cb, divisor_abs_word.x_word()); + let remainder_is_zero = IsZeroWordGadget::construct(cb, remainder_abs_word.x_word()); - cb.stack_pop(dividend_abs_word.x().expr()); - cb.stack_pop(divisor_abs_word.x().expr()); - cb.stack_push(select::expr( + cb.stack_pop_word(dividend_abs_word.x_word().to_word()); + cb.stack_pop_word(divisor_abs_word.x_word().to_word()); + cb.stack_push_word(Word::select( is_sdiv, - quotient_abs_word.x().expr() * (1.expr() - divisor_is_zero.expr()), - remainder_abs_word.x().expr() * (1.expr() - divisor_is_zero.expr()), + quotient_abs_word + .x_word() + .to_word() + .mul_selector(1.expr() - divisor_is_zero.expr()), + remainder_abs_word + .x_word() + .to_word() + .mul_selector(1.expr() - divisor_is_zero.expr()), )); // Constrain `|quotient| * |divisor| + |remainder| = |dividend|`. let mul_add_words = MulAddWordsGadget::construct( cb, [ - quotient_abs_word.x_abs(), - divisor_abs_word.x_abs(), - remainder_abs_word.x_abs(), - dividend_abs_word.x_abs(), + quotient_abs_word.x_abs_word(), + divisor_abs_word.x_abs_word(), + remainder_abs_word.x_abs_word(), + dividend_abs_word.x_abs_word(), ], ); cb.add_constraint("overflow == 0", mul_add_words.overflow()); - let remainder_abs_lt_divisor_abs = - LtWordGadget::construct(cb, remainder_abs_word.x_abs(), divisor_abs_word.x_abs()); + let remainder_abs_lt_divisor_abs = LtWordGadget::construct( + cb, + &remainder_abs_word.x_abs_word().to_word(), + &divisor_abs_word.x_abs_word().to_word(), + ); cb.add_constraint( "abs(remainder) < abs(divisor) when divisor != 0", (1.expr() - remainder_abs_lt_divisor_abs.expr()) * (1.expr() - divisor_is_zero.expr()), @@ -95,8 +108,11 @@ impl ExecutionGadget for SignedDivModGadget { // `(1 << 255) - 1`. So constraint // `sign(dividend) == sign(divisor) ^ sign(quotient)` cannot be applied // for this case. - let dividend_is_signed_overflow = - LtGadget::construct(cb, 127.expr(), dividend_abs_word.x_abs().cells[31].expr()); + let dividend_is_signed_overflow = LtGadget::construct( + cb, + 127.expr(), + dividend_abs_word.x_abs_word().limbs[31].expr(), + ); // Constrain sign(dividend) == sign(divisor) ^ sign(quotient) when both // quotient and divisor are non-zero and dividend is not signed overflow. @@ -206,15 +222,12 @@ impl ExecutionGadget for SignedDivModGadget { 127.into(), u64::from(dividend_abs.to_le_bytes()[31]).into(), )?; - let quotient_sum = (0..32).fold(0, |acc, idx| acc + quotient.byte(idx) as u64); - let divisor_sum = (0..32).fold(0, |acc, idx| acc + divisor.byte(idx) as u64); - let remainder_sum = (0..32).fold(0, |acc, idx| acc + remainder.byte(idx) as u64); self.quotient_is_zero - .assign(region, offset, F::from(quotient_sum))?; + .assign(region, offset, Word::from(quotient))?; self.divisor_is_zero - .assign(region, offset, F::from(divisor_sum))?; + .assign(region, offset, Word::from(divisor))?; self.remainder_is_zero - .assign(region, offset, F::from(remainder_sum))?; + .assign(region, offset, Word::from(remainder))?; Ok(()) } } diff --git a/zkevm-circuits/src/evm_circuit/execution/selfbalance.rs b/zkevm-circuits/src/evm_circuit/execution/selfbalance.rs index b170e88360..ab47f90448 100644 --- a/zkevm-circuits/src/evm_circuit/execution/selfbalance.rs +++ b/zkevm-circuits/src/evm_circuit/execution/selfbalance.rs @@ -5,22 +5,25 @@ use crate::{ util::{ common_gadget::SameContextGadget, constraint_builder::{EVMConstraintBuilder, StepStateTransition, Transition::Delta}, - CachedRegion, Cell, + CachedRegion, }, witness::{Block, Call, ExecStep, Transaction}, }, table::{AccountFieldTag, CallContextFieldTag}, - util::Expr, + util::{ + word::{WordCell, WordExpr}, + Expr, + }, }; use bus_mapping::evm::OpcodeId; -use eth_types::{Field, ToScalar}; -use halo2_proofs::{circuit::Value, plonk::Error}; +use eth_types::Field; +use halo2_proofs::plonk::Error; #[derive(Clone, Debug)] pub(crate) struct SelfbalanceGadget { same_context: SameContextGadget, - callee_address: Cell, - phase2_self_balance: Cell, + callee_address: WordCell, + self_balance: WordCell, } impl ExecutionGadget for SelfbalanceGadget { @@ -29,16 +32,16 @@ impl ExecutionGadget for SelfbalanceGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::SELFBALANCE; fn configure(cb: &mut EVMConstraintBuilder) -> Self { - let callee_address = cb.call_context(None, CallContextFieldTag::CalleeAddress); + let callee_address = cb.call_context_read_as_word(None, CallContextFieldTag::CalleeAddress); - let phase2_self_balance = cb.query_cell_phase2(); - cb.account_read( - callee_address.expr(), + let self_balance = cb.query_word_unchecked(); + cb.account_read_word( + callee_address.to_word(), AccountFieldTag::Balance, - phase2_self_balance.expr(), + self_balance.to_word(), ); - cb.stack_push(phase2_self_balance.expr()); + cb.stack_push_word(self_balance.to_word()); let opcode = cb.query_cell(); let step_state_transition = StepStateTransition { @@ -52,8 +55,8 @@ impl ExecutionGadget for SelfbalanceGadget { Self { same_context, - phase2_self_balance, callee_address, + self_balance, } } @@ -68,19 +71,12 @@ impl ExecutionGadget for SelfbalanceGadget { ) -> Result<(), Error> { self.same_context.assign_exec_step(region, offset, step)?; - self.callee_address.assign( - region, - offset, - Value::known( - call.address - .to_scalar() - .expect("unexpected Address -> Scalar conversion failure"), - ), - )?; + self.callee_address + .assign_h160(region, offset, call.address)?; let self_balance = block.get_rws(step, 2).stack_value(); - self.phase2_self_balance - .assign(region, offset, region.word_rlc(self_balance))?; + self.self_balance + .assign_u256(region, offset, self_balance)?; Ok(()) } diff --git a/zkevm-circuits/src/evm_circuit/execution/sha3.rs b/zkevm-circuits/src/evm_circuit/execution/sha3.rs index 736b961dfa..79a21175ce 100644 --- a/zkevm-circuits/src/evm_circuit/execution/sha3.rs +++ b/zkevm-circuits/src/evm_circuit/execution/sha3.rs @@ -1,20 +1,23 @@ use bus_mapping::{circuit_input_builder::CopyDataType, evm::OpcodeId}; -use eth_types::{evm_types::GasCost, Field, ToLittleEndian, ToScalar}; +use eth_types::{evm_types::GasCost, Field, ToScalar}; use gadgets::util::{not, Expr}; use halo2_proofs::{circuit::Value, plonk::Error}; -use crate::evm_circuit::{ - param::N_BYTES_MEMORY_WORD_SIZE, - step::ExecutionState, - util::{ - common_gadget::SameContextGadget, - constraint_builder::{ - ConstrainBuilderCommon, EVMConstraintBuilder, StepStateTransition, Transition, +use crate::{ + evm_circuit::{ + param::N_BYTES_MEMORY_WORD_SIZE, + step::ExecutionState, + util::{ + common_gadget::SameContextGadget, + constraint_builder::{ + ConstrainBuilderCommon, EVMConstraintBuilder, StepStateTransition, Transition, + }, + memory_gadget::{MemoryAddressGadget, MemoryCopierGasGadget, MemoryExpansionGadget}, + rlc, CachedRegion, Cell, }, - memory_gadget::{MemoryAddressGadget, MemoryCopierGasGadget, MemoryExpansionGadget}, - rlc, CachedRegion, Cell, Word, + witness::{Block, Call, ExecStep, Transaction}, }, - witness::{Block, Call, ExecStep, Transaction}, + util::word::{Word, WordCell, WordExpr}, }; use super::ExecutionGadget; @@ -23,7 +26,7 @@ use super::ExecutionGadget; pub(crate) struct Sha3Gadget { same_context: SameContextGadget, memory_address: MemoryAddressGadget, - sha3_rlc: Word, + sha3_digest: WordCell, copy_rwc_inc: Cell, rlc_acc: Cell, memory_expansion: MemoryExpansionGadget, @@ -38,13 +41,13 @@ impl ExecutionGadget for Sha3Gadget { fn configure(cb: &mut EVMConstraintBuilder) -> Self { let opcode = cb.query_cell(); - let offset = cb.query_cell_phase2(); - let size = cb.query_word_rlc(); - let sha3_rlc = cb.query_word_rlc(); + let offset = cb.query_word_unchecked(); + let size = cb.query_memory_address(); + let sha3_digest = cb.query_word_unchecked(); - cb.stack_pop(offset.expr()); - cb.stack_pop(size.expr()); - cb.stack_push(sha3_rlc.expr()); + cb.stack_pop_word(offset.to_word()); + cb.stack_pop_word(size.to_word()); + cb.stack_push_word(sha3_digest.to_word()); let memory_address = MemoryAddressGadget::construct(cb, offset, size); @@ -53,9 +56,9 @@ impl ExecutionGadget for Sha3Gadget { cb.condition(memory_address.has_length(), |cb| { cb.copy_table_lookup( - cb.curr.state.call_id.expr(), + Word::from_lo_unchecked(cb.curr.state.call_id.expr()), CopyDataType::Memory.expr(), - cb.curr.state.call_id.expr(), + Word::from_lo_unchecked(cb.curr.state.call_id.expr()), CopyDataType::RlcAcc.expr(), memory_address.offset(), memory_address.address(), @@ -70,7 +73,11 @@ impl ExecutionGadget for Sha3Gadget { 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()); }); - cb.keccak_table_lookup(rlc_acc.expr(), memory_address.length(), sha3_rlc.expr()); + cb.keccak_table_lookup_word( + rlc_acc.expr(), + memory_address.length(), + sha3_digest.to_word(), + ); let memory_expansion = MemoryExpansionGadget::construct(cb, [memory_address.address()]); let memory_copier_gas = MemoryCopierGasGadget::construct( @@ -94,7 +101,7 @@ impl ExecutionGadget for Sha3Gadget { Self { same_context, memory_address, - sha3_rlc, + sha3_digest, copy_rwc_inc, rlc_acc, memory_expansion, @@ -118,8 +125,7 @@ impl ExecutionGadget for Sha3Gadget { let memory_address = self .memory_address .assign(region, offset, memory_offset, size)?; - self.sha3_rlc - .assign(region, offset, Some(sha3_output.to_le_bytes()))?; + self.sha3_digest.assign_u256(region, offset, sha3_output)?; self.copy_rwc_inc.assign( region, diff --git a/zkevm-circuits/src/evm_circuit/execution/shl_shr.rs b/zkevm-circuits/src/evm_circuit/execution/shl_shr.rs index 798a1101fe..f5512daf61 100644 --- a/zkevm-circuits/src/evm_circuit/execution/shl_shr.rs +++ b/zkevm-circuits/src/evm_circuit/execution/shl_shr.rs @@ -4,19 +4,20 @@ use crate::{ step::ExecutionState, table::{FixedTableTag, Lookup}, util::{ - self, common_gadget::SameContextGadget, constraint_builder::{ ConstrainBuilderCommon, EVMConstraintBuilder, StepStateTransition, Transition::Delta, }, - from_bytes, - math_gadget::{IsZeroGadget, LtWordGadget, MulAddWordsGadget}, + math_gadget::{IsZeroGadget, IsZeroWordGadget, LtWordGadget, MulAddWordsGadget}, sum, CachedRegion, Cell, }, witness::{Block, Call, ExecStep, Transaction}, }, - util::Expr, + util::{ + word::{Word, Word32Cell, WordExpr}, + Expr, + }, }; use bus_mapping::evm::OpcodeId; use eth_types::{Field, ToLittleEndian, U256}; @@ -29,12 +30,12 @@ use halo2_proofs::{circuit::Value, plonk::Error}; #[derive(Clone, Debug)] pub(crate) struct ShlShrGadget { same_context: SameContextGadget, - quotient: util::Word, - divisor: util::Word, - remainder: util::Word, - dividend: util::Word, + quotient: Word32Cell, + divisor: Word32Cell, + remainder: Word32Cell, + dividend: Word32Cell, /// Shift word - shift: util::Word, + shift: Word32Cell, /// First byte of shift word shf0: Cell, /// Gadget that verifies quotient * divisor + remainder = dividend @@ -42,9 +43,9 @@ pub(crate) struct ShlShrGadget { /// Identify if `shift` is less than 256 or not shf_lt256: IsZeroGadget, /// Check if divisor is zero - divisor_is_zero: IsZeroGadget, + divisor_is_zero: IsZeroWordGadget>, /// Check if remainder is zero - remainder_is_zero: IsZeroGadget, + remainder_is_zero: IsZeroWordGadget>, /// Check if remainder < divisor when divisor != 0 remainder_lt_divisor: LtWordGadget, } @@ -59,38 +60,50 @@ 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_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 quotient = cb.query_word32(); + let divisor = cb.query_word32(); + let remainder = cb.query_word32(); + let dividend = cb.query_word32(); + let shift = cb.query_word32(); let shf0 = cb.query_cell(); let mul_add_words = MulAddWordsGadget::construct(cb, ["ient, &divisor, &remainder, ÷nd]); - let shf_lt256 = IsZeroGadget::construct(cb, sum::expr(&shift.cells[1..32])); - let divisor_is_zero = IsZeroGadget::construct(cb, sum::expr(&divisor.cells)); - let remainder_is_zero = IsZeroGadget::construct(cb, sum::expr(&remainder.cells)); - let remainder_lt_divisor = LtWordGadget::construct(cb, &remainder, &divisor); + let shf_lt256 = IsZeroGadget::construct(cb, sum::expr(&shift.limbs[1..32])); + let divisor_is_zero = IsZeroWordGadget::construct(cb, &divisor); + let remainder_is_zero = IsZeroWordGadget::construct(cb, &remainder); + let remainder_lt_divisor = + LtWordGadget::construct(cb, &remainder.to_word(), &divisor.to_word()); // Constrain stack pops and pushes as: // - for SHL, two pops are shift and quotient, and push is dividend. // - for SHR, two pops are shift and dividend, and push is quotient. - cb.stack_pop(shift.expr()); - cb.stack_pop(is_shl.expr() * quotient.expr() + is_shr.expr() * dividend.expr()); - cb.stack_push( - (is_shl.expr() * dividend.expr() + is_shr.expr() * quotient.expr()) - * (1.expr() - divisor_is_zero.expr()), + cb.stack_pop_word(shift.to_word()); + cb.stack_pop_word( + quotient + .to_word() + .mul_selector(is_shl.expr()) + .add_unchecked(dividend.to_word().mul_selector(is_shr.expr())), + ); + cb.stack_push_word( + (dividend + .to_word() + .mul_selector(is_shl.expr()) + .add_unchecked(quotient.to_word().mul_selector(is_shr.expr()))) + .mul_selector(1.expr() - divisor_is_zero.expr()), ); cb.require_zero( "shf0 == shift.cells[0]", - shf0.expr() - shift.cells[0].expr(), + shf0.expr() - shift.limbs[0].expr(), ); - cb.require_zero( + cb.require_zero_word( "shift == shift.cells[0] when divisor != 0", - (1.expr() - divisor_is_zero.expr()) * (shift.expr() - shift.cells[0].expr()), + shift + .to_word() + .sub_unchecked(Word::from_lo_unchecked(shift.limbs[0].expr())) + .mul_selector(1.expr() - divisor_is_zero.expr()), ); cb.require_zero( @@ -115,8 +128,7 @@ impl ExecutionGadget for ShlShrGadget { // Constrain divisor_lo == 2^shf0 when shf0 < 128, and // divisor_hi == 2^(128 - shf0) otherwise. - let divisor_lo = from_bytes::expr(&divisor.cells[..16]); - let divisor_hi = from_bytes::expr(&divisor.cells[16..]); + let (divisor_lo, divisor_hi) = divisor.to_word().to_lo_hi(); cb.condition(1.expr() - divisor_is_zero.expr(), |cb| { cb.add_lookup( "Pow2 lookup of shf0, divisor_lo and divisor_hi", @@ -184,27 +196,20 @@ impl ExecutionGadget for ShlShrGadget { OpcodeId::SHR => (push, pop2 - push * divisor, pop2), _ => unreachable!(), }; - self.quotient - .assign(region, offset, Some(quotient.to_le_bytes()))?; - self.divisor - .assign(region, offset, Some(divisor.to_le_bytes()))?; - self.remainder - .assign(region, offset, Some(remainder.to_le_bytes()))?; - self.dividend - .assign(region, offset, Some(dividend.to_le_bytes()))?; - self.shift - .assign(region, offset, Some(pop1.to_le_bytes()))?; + self.quotient.assign_u256(region, offset, quotient)?; + self.divisor.assign_u256(region, offset, divisor)?; + self.remainder.assign_u256(region, offset, remainder)?; + self.dividend.assign_u256(region, offset, dividend)?; + self.shift.assign_u256(region, offset, pop1)?; self.shf0 .assign(region, offset, Value::known(F::from(shf0)))?; self.mul_add_words .assign(region, offset, [quotient, divisor, remainder, dividend])?; self.shf_lt256.assign(region, offset, F::from(shf_lt256))?; - let divisor_sum = (0..32).fold(0, |acc, idx| acc + divisor.byte(idx) as u64); self.divisor_is_zero - .assign(region, offset, F::from(divisor_sum))?; - let remainder_sum = (0..32).fold(0, |acc, idx| acc + remainder.byte(idx) as u64); + .assign(region, offset, Word::from(divisor))?; self.remainder_is_zero - .assign(region, offset, F::from(remainder_sum))?; + .assign(region, offset, Word::from(remainder))?; self.remainder_lt_divisor .assign(region, offset, remainder, divisor) } diff --git a/zkevm-circuits/src/evm_circuit/execution/signed_comparator.rs b/zkevm-circuits/src/evm_circuit/execution/signed_comparator.rs index 8ee8357385..207f721f73 100644 --- a/zkevm-circuits/src/evm_circuit/execution/signed_comparator.rs +++ b/zkevm-circuits/src/evm_circuit/execution/signed_comparator.rs @@ -7,11 +7,14 @@ use crate::{ constraint_builder::{EVMConstraintBuilder, StepStateTransition, Transition::Delta}, from_bytes, math_gadget::{ComparisonGadget, IsEqualGadget, LtGadget}, - select, CachedRegion, Cell, Word, + select, CachedRegion, Cell, }, witness::{Block, Call, ExecStep, Transaction}, }, - util::Expr, + util::{ + word::{Word, Word32Cell, WordExpr}, + Expr, + }, }; use eth_types::{evm_types::OpcodeId, Field, ToLittleEndian}; use halo2_proofs::{circuit::Value, plonk::Error}; @@ -22,8 +25,8 @@ use halo2_proofs::{circuit::Value, plonk::Error}; pub(crate) struct SignedComparatorGadget { same_context: SameContextGadget, - a: Word, - b: Word, + a: Word32Cell, + b: Word32Cell, sign_check_a: LtGadget, sign_check_b: LtGadget, @@ -42,8 +45,8 @@ impl ExecutionGadget for SignedComparatorGadget { fn configure(cb: &mut EVMConstraintBuilder) -> Self { let opcode = cb.query_cell(); - let a = cb.query_word_rlc(); - let b = cb.query_word_rlc(); + let a = cb.query_word32(); + let b = cb.query_word32(); // The Signed Comparator gadget is used for both opcodes SLT and SGT. // Depending on whether the opcode is SLT or SGT, we @@ -56,8 +59,8 @@ impl ExecutionGadget for SignedComparatorGadget { // number is negative if the most significant cell >= 128 // (0b10000000). a and b being in the little-endian notation, the // most-significant byte is the last byte. - let sign_check_a = LtGadget::construct(cb, a.cells[31].expr(), 128.expr()); - let sign_check_b = LtGadget::construct(cb, b.cells[31].expr(), 128.expr()); + let sign_check_a = LtGadget::construct(cb, a.limbs[31].expr(), 128.expr()); + let sign_check_b = LtGadget::construct(cb, b.limbs[31].expr(), 128.expr()); // sign_check_a_lt expression implies a is positive since its MSB < 2**7 // sign_check_b_lt expression implies b is positive since its MSB < 2**7 @@ -72,16 +75,10 @@ impl ExecutionGadget for SignedComparatorGadget { // significant bytes. While only considering the absolute // values, we have: a < b == 1 iff ((a_hi < b_hi) || ((a_hi == // b_hi) && (a_lo < b_lo))) - let lt_lo = LtGadget::construct( - cb, - from_bytes::expr(&a.cells[0..16]), - from_bytes::expr(&b.cells[0..16]), - ); - let comparison_hi = ComparisonGadget::construct( - cb, - from_bytes::expr(&a.cells[16..32]), - from_bytes::expr(&b.cells[16..32]), - ); + let (a_lo, a_hi) = a.to_word().to_lo_hi(); + let (b_lo, b_hi) = b.to_word().to_lo_hi(); + let lt_lo = LtGadget::construct(cb, a_lo, b_lo); + let comparison_hi = ComparisonGadget::construct(cb, a_hi, b_hi); let a_lt_b_lo = lt_lo.expr(); let (a_lt_b_hi, a_eq_b_hi) = comparison_hi.expr(); @@ -112,9 +109,9 @@ impl ExecutionGadget for SignedComparatorGadget { let result = a_neg_b_pos.clone() + (1.expr() - a_neg_b_pos - b_neg_a_pos) * a_lt_b.expr(); // Pop a and b from the stack, push the result on the stack. - cb.stack_pop(select::expr(is_sgt.expr(), b.expr(), a.expr())); - cb.stack_pop(select::expr(is_sgt.expr(), a.expr(), b.expr())); - cb.stack_push(result); + cb.stack_pop_word(Word::select(is_sgt.expr(), b.to_word(), a.to_word())); + cb.stack_pop_word(Word::select(is_sgt.expr(), a.to_word(), b.to_word())); + cb.stack_push_word(Word::from_lo_unchecked(result)); // The read-write counter changes by three since we're reading two words // from stack and writing one. The program counter shifts only by one @@ -209,8 +206,8 @@ impl ExecutionGadget for SignedComparatorGadget { Value::known(if a < b { F::ONE } else { F::ZERO }), )?; - self.a.assign(region, offset, Some(a_le_bytes))?; - self.b.assign(region, offset, Some(b_le_bytes))?; + self.a.assign_u256(region, offset, a)?; + self.b.assign_u256(region, offset, b)?; Ok(()) } diff --git a/zkevm-circuits/src/evm_circuit/execution/signextend.rs b/zkevm-circuits/src/evm_circuit/execution/signextend.rs index ba16143688..2abaa64aed 100644 --- a/zkevm-circuits/src/evm_circuit/execution/signextend.rs +++ b/zkevm-circuits/src/evm_circuit/execution/signextend.rs @@ -11,11 +11,14 @@ use crate::{ Transition::Delta, }, math_gadget::{IsEqualGadget, IsZeroGadget}, - rlc, select, sum, CachedRegion, Cell, Word, + select, sum, CachedRegion, Cell, }, witness::{Block, Call, ExecStep, Transaction}, }, - util::Expr, + util::{ + word::{Word32, Word32Cell, WordExpr}, + Expr, + }, }; use array_init::array_init; use bus_mapping::evm::OpcodeId; @@ -25,8 +28,8 @@ use halo2_proofs::{circuit::Value, plonk::Error}; #[derive(Clone, Debug)] pub(crate) struct SignextendGadget { same_context: SameContextGadget, - index: Word, - value: Word, + index: Word32Cell, + value: Word32Cell, sign_byte: Cell, is_msb_sum_zero: IsZeroGadget, is_byte_selected: [IsEqualGadget; 31], @@ -39,8 +42,8 @@ impl ExecutionGadget for SignextendGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::SIGNEXTEND; fn configure(cb: &mut EVMConstraintBuilder) -> Self { - let index = cb.query_word_rlc(); - let value = cb.query_word_rlc(); + let index = cb.query_word32(); + let value = cb.query_word32(); let sign_byte = cb.query_cell(); let selectors = array_init(|_| cb.query_bool()); @@ -49,12 +52,12 @@ impl ExecutionGadget for SignextendGadget { // need to do any changes. So just sum all the non-LSB byte // values here and then check if it's non-zero so we can use // that as an additional condition to enable the selector. - let is_msb_sum_zero = IsZeroGadget::construct(cb, sum::expr(&index.cells[1..32])); + let is_msb_sum_zero = IsZeroGadget::construct(cb, sum::expr(&index.limbs[1..32])); // Check if this byte is selected looking only at the LSB of the index // word let is_byte_selected = - array_init(|idx| IsEqualGadget::construct(cb, index.cells[0].expr(), idx.expr())); + array_init(|idx| IsEqualGadget::construct(cb, index.limbs[0].expr(), idx.expr())); // We need to find the byte we have to get the sign from so we can // extend correctly. We go byte by byte and check if `idx == @@ -72,7 +75,7 @@ impl ExecutionGadget for SignextendGadget { let is_selected = and::expr(&[is_byte_selected[idx].expr(), is_msb_sum_zero.expr()]); // Add the byte to the sum when this byte is selected - selected_byte = selected_byte + (is_selected.clone() * value.cells[idx].expr()); + selected_byte = selected_byte + (is_selected.clone() * value.limbs[idx].expr()); // Verify the selector. // Cells are used here to store intermediate results, otherwise @@ -111,26 +114,23 @@ 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 result = rlc::expr( - &array_init::<_, _, 32>(|idx| { - if idx == 0 { - value.cells[idx].expr() - } else { - select::expr( - selectors[idx - 1].expr(), - sign_byte.expr(), - value.cells[idx].expr(), - ) - } - }), - cb.challenges().evm_word(), - ); + let result = Word32::new(array_init::<_, _, 32>(|idx| { + if idx == 0 { + value.limbs[idx].expr() + } else { + select::expr( + selectors[idx - 1].expr(), + sign_byte.expr(), + value.limbs[idx].expr(), + ) + } + })); // Pop the byte index and the value from the stack, push the result on // the stack - cb.stack_pop(index.expr()); - cb.stack_pop(value.expr()); - cb.stack_push(result); + cb.stack_pop_word(index.to_word()); + cb.stack_pop_word(value.to_word()); + cb.stack_push_word(result.to_word()); // State transition let step_state_transition = StepStateTransition { @@ -166,22 +166,24 @@ impl ExecutionGadget for SignextendGadget { self.same_context.assign_exec_step(region, offset, step)?; // Inputs/Outputs - let index = block.get_rws(step, 0).stack_value().to_le_bytes(); - let value = block.get_rws(step, 1).stack_value().to_le_bytes(); - self.index.assign(region, offset, Some(index))?; - self.value.assign(region, offset, Some(value))?; + let index = block.get_rws(step, 0).stack_value(); + let index_bytes = index.to_le_bytes(); + let value = block.get_rws(step, 1).stack_value(); + let value_bytes = value.to_le_bytes(); + self.index.assign_u256(region, offset, index)?; + self.value.assign_u256(region, offset, value)?; // Generate the selectors let msb_sum_zero = self.is_msb_sum_zero - .assign(region, offset, sum::value(&index[1..32]))?; + .assign(region, offset, sum::value(&index_bytes[1..32]))?; let mut previous_selector_value: F = 0.into(); for i in 0..31 { let selected = and::value(vec![ self.is_byte_selected[i].assign( region, offset, - F::from(index[0] as u64), + F::from(index_bytes[0] as u64), F::from(i as u64), )?, msb_sum_zero, @@ -195,8 +197,8 @@ impl ExecutionGadget for SignextendGadget { // Set the sign byte let mut sign = 0u64; - if index[0] < 31 && msb_sum_zero == F::ONE { - sign = (value[index[0] as usize] >> 7) as u64; + if index_bytes[0] < 31 && msb_sum_zero == F::ONE { + sign = (value_bytes[index_bytes[0] as usize] >> 7) as u64; } self.sign_byte .assign(region, offset, Value::known(F::from(sign * 0xFF))) diff --git a/zkevm-circuits/src/evm_circuit/execution/sload.rs b/zkevm-circuits/src/evm_circuit/execution/sload.rs index 32759f9aa1..795f015fd2 100644 --- a/zkevm-circuits/src/evm_circuit/execution/sload.rs +++ b/zkevm-circuits/src/evm_circuit/execution/sload.rs @@ -12,9 +12,12 @@ use crate::{ witness::{Block, Call, ExecStep, Transaction}, }, table::CallContextFieldTag, - util::Expr, + util::{ + word::{Word, WordCell, WordExpr}, + Expr, + }, }; -use eth_types::{Field, ToScalar}; +use eth_types::Field; use halo2_proofs::{circuit::Value, plonk::Error}; #[derive(Clone, Debug)] @@ -22,10 +25,10 @@ pub(crate) struct SloadGadget { same_context: SameContextGadget, tx_id: Cell, reversion_info: ReversionInfo, - callee_address: Cell, - phase2_key: Cell, - phase2_value: Cell, - phase2_committed_value: Cell, + callee_address: WordCell, + key: WordCell, + value: WordCell, + committed_value: WordCell, is_warm: Cell, } @@ -39,31 +42,31 @@ impl ExecutionGadget for SloadGadget { let tx_id = cb.call_context(None, CallContextFieldTag::TxId); let mut reversion_info = cb.reversion_info_read(None); - let callee_address = cb.call_context(None, CallContextFieldTag::CalleeAddress); + let callee_address = cb.call_context_read_as_word(None, CallContextFieldTag::CalleeAddress); - let phase2_key = cb.query_cell_phase2(); + let key = cb.query_word_unchecked(); // Pop the key from the stack - cb.stack_pop(phase2_key.expr()); - - let phase2_value = cb.query_cell_phase2(); - let phase2_committed_value = cb.query_cell_phase2(); - cb.account_storage_read( - callee_address.expr(), - phase2_key.expr(), - phase2_value.expr(), + cb.stack_pop_word(key.to_word()); + + let value = cb.query_word_unchecked(); + let committed_value = cb.query_word_unchecked(); + cb.account_storage_read_word( + callee_address.to_word(), + key.to_word(), + value.to_word(), tx_id.expr(), - phase2_committed_value.expr(), + committed_value.to_word(), ); - cb.stack_push(phase2_value.expr()); + cb.stack_push_word(value.to_word()); let is_warm = cb.query_bool(); - cb.account_storage_access_list_write( + cb.account_storage_access_list_write_word( tx_id.expr(), - callee_address.expr(), - phase2_key.expr(), - true.expr(), - is_warm.expr(), + callee_address.to_word(), + key.to_word(), + Word::from_lo_unchecked(true.expr()), + Word::from_lo_unchecked(is_warm.expr()), Some(&mut reversion_info), ); @@ -82,9 +85,9 @@ impl ExecutionGadget for SloadGadget { tx_id, reversion_info, callee_address, - phase2_key, - phase2_value, - phase2_committed_value, + key, + value, + committed_value, is_warm, } } @@ -108,25 +111,17 @@ impl ExecutionGadget for SloadGadget { call.rw_counter_end_of_reversion, call.is_persistent, )?; - self.callee_address.assign( - region, - offset, - Value::known( - call.address - .to_scalar() - .expect("unexpected Address -> Scalar conversion failure"), - ), - )?; + self.callee_address + .assign_h160(region, offset, call.address)?; + let key = block.get_rws(step, 4).stack_value(); let value = block.get_rws(step, 6).stack_value(); - self.phase2_key - .assign(region, offset, region.word_rlc(key))?; - self.phase2_value - .assign(region, offset, region.word_rlc(value))?; + self.key.assign_u256(region, offset, key)?; + self.value.assign_u256(region, offset, value)?; let (_, committed_value) = block.get_rws(step, 5).aux_pair(); - self.phase2_committed_value - .assign(region, offset, region.word_rlc(committed_value))?; + self.committed_value + .assign_u256(region, offset, committed_value)?; let (_, is_warm) = block.get_rws(step, 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 fd0a90b558..b172b963aa 100644 --- a/zkevm-circuits/src/evm_circuit/execution/sstore.rs +++ b/zkevm-circuits/src/evm_circuit/execution/sstore.rs @@ -9,16 +9,19 @@ use crate::{ ConstrainBuilderCommon, EVMConstraintBuilder, ReversionInfo, StepStateTransition, Transition::Delta, }, - math_gadget::{IsEqualGadget, IsZeroGadget, LtGadget}, - not, CachedRegion, Cell, + math_gadget::{IsEqualWordGadget, IsZeroWordGadget, LtGadget}, + not, CachedRegion, Cell, U64Cell, }, witness::{Block, Call, ExecStep, Transaction}, }, table::CallContextFieldTag, - util::Expr, + util::{ + word::{Word, Word32Cell, WordCell, WordExpr}, + Expr, + }, }; -use eth_types::{evm_types::GasCost, Field, ToScalar}; +use eth_types::{evm_types::GasCost, Field}; use halo2_proofs::{ circuit::Value, plonk::{Error, Expression}, @@ -30,16 +33,16 @@ pub(crate) struct SstoreGadget { tx_id: Cell, is_static: Cell, reversion_info: ReversionInfo, - callee_address: Cell, - phase2_key: Cell, - phase2_value: Cell, - phase2_value_prev: Cell, - phase2_original_value: Cell, + callee_address: WordCell, + key: Word32Cell, + value: Word32Cell, + value_prev: Word32Cell, + original_value: Word32Cell, is_warm: Cell, - tx_refund_prev: Cell, + tx_refund_prev: U64Cell, // Constrain for SSTORE reentrancy sentry. sufficient_gas_sentry: LtGadget, - gas_cost: SstoreGasGadget, + gas_cost: SstoreGasGadget>, tx_refund: SstoreTxRefundGadget, } @@ -58,35 +61,35 @@ impl ExecutionGadget for SstoreGadget { cb.require_zero("is_static is false", is_static.expr()); let mut reversion_info = cb.reversion_info_read(None); - let callee_address = cb.call_context(None, CallContextFieldTag::CalleeAddress); + let callee_address = cb.call_context_read_as_word(None, CallContextFieldTag::CalleeAddress); - let phase2_key = cb.query_cell_phase2(); + let key = cb.query_word32(); // Pop the key from the stack - cb.stack_pop(phase2_key.expr()); + cb.stack_pop_word(key.to_word()); - let phase2_value = cb.query_cell_phase2(); + let value = cb.query_word32(); // Pop the value from the stack - cb.stack_pop(phase2_value.expr()); - - let phase2_value_prev = cb.query_cell_phase2(); - let phase2_original_value = cb.query_cell_phase2(); - cb.account_storage_write( - callee_address.expr(), - phase2_key.expr(), - phase2_value.expr(), - phase2_value_prev.expr(), + cb.stack_pop_word(value.to_word()); + + let value_prev = cb.query_word32(); + let original_value = cb.query_word32(); + cb.account_storage_write_word( + callee_address.to_word(), + key.to_word(), + value.to_word(), + value_prev.to_word(), tx_id.expr(), - phase2_original_value.expr(), + original_value.to_word(), Some(&mut reversion_info), ); let is_warm = cb.query_bool(); - cb.account_storage_access_list_write( + cb.account_storage_access_list_write_word( tx_id.expr(), - callee_address.expr(), - phase2_key.expr(), - true.expr(), - is_warm.expr(), + callee_address.to_word(), + key.to_word(), + Word::from_lo_unchecked(true.expr()), + Word::from_lo_unchecked(is_warm.expr()), Some(&mut reversion_info), ); @@ -104,24 +107,24 @@ impl ExecutionGadget for SstoreGadget { let gas_cost = SstoreGasGadget::construct( cb, - phase2_value.clone(), - phase2_value_prev.clone(), - phase2_original_value.clone(), is_warm.clone(), + value.clone(), + value_prev.clone(), + original_value.clone(), ); - let tx_refund_prev = cb.query_cell(); + let tx_refund_prev = cb.query_u64(); let tx_refund = SstoreTxRefundGadget::construct( cb, tx_refund_prev.clone(), - phase2_value.clone(), - phase2_value_prev.clone(), - phase2_original_value.clone(), + value.clone(), + value_prev.clone(), + original_value.clone(), ); - cb.tx_refund_write( + cb.tx_refund_write_word( tx_id.expr(), - tx_refund.expr(), - tx_refund_prev.expr(), + Word::from_lo_unchecked(tx_refund.expr()), + tx_refund_prev.to_word(), Some(&mut reversion_info), ); @@ -141,10 +144,10 @@ impl ExecutionGadget for SstoreGadget { is_static, reversion_info, callee_address, - phase2_key, - phase2_value, - phase2_value_prev, - phase2_original_value, + key, + value, + value_prev, + original_value, is_warm, tx_refund_prev, sufficient_gas_sentry, @@ -174,28 +177,18 @@ impl ExecutionGadget for SstoreGadget { call.rw_counter_end_of_reversion, call.is_persistent, )?; - self.callee_address.assign( - region, - offset, - Value::known( - call.address - .to_scalar() - .expect("unexpected Address -> Scalar conversion failure"), - ), - )?; + self.callee_address + .assign_h160(region, offset, call.address)?; let key = block.get_rws(step, 5).stack_value(); let value = block.get_rws(step, 6).stack_value(); - self.phase2_key - .assign(region, offset, region.word_rlc(key))?; - self.phase2_value - .assign(region, offset, region.word_rlc(value))?; + self.key.assign_u256(region, offset, key)?; + self.value.assign_u256(region, offset, value)?; let (_, value_prev, _, original_value) = block.get_rws(step, 7).storage_value_aux(); - self.phase2_value_prev - .assign(region, offset, region.word_rlc(value_prev))?; - self.phase2_original_value - .assign(region, offset, region.word_rlc(original_value))?; + self.value_prev.assign_u256(region, offset, value_prev)?; + self.original_value + .assign_u256(region, offset, original_value)?; let (_, is_warm) = block.get_rws(step, 8).tx_access_list_value_pair(); self.is_warm @@ -203,7 +196,7 @@ impl ExecutionGadget for SstoreGadget { let (tx_refund, tx_refund_prev) = block.get_rws(step, 9).tx_refund_value_pair(); self.tx_refund_prev - .assign(region, offset, Value::known(F::from(tx_refund_prev)))?; + .assign(region, offset, Some(tx_refund_prev.to_le_bytes()))?; self.sufficient_gas_sentry.assign_value( region, @@ -230,36 +223,34 @@ impl ExecutionGadget for SstoreGadget { #[derive(Clone, Debug)] pub(crate) struct SstoreTxRefundGadget { - tx_refund_old: Cell, + tx_refund_old: U64Cell, tx_refund_new: Expression, - value: Cell, - value_prev: Cell, - original_value: Cell, - value_prev_is_zero_gadget: IsZeroGadget, - value_is_zero_gadget: IsZeroGadget, - original_is_zero_gadget: IsZeroGadget, - original_eq_value_gadget: IsEqualGadget, - prev_eq_value_gadget: IsEqualGadget, - original_eq_prev_gadget: IsEqualGadget, + value_prev_is_zero_gadget: IsZeroWordGadget>>, + value_is_zero_gadget: IsZeroWordGadget>>, + original_is_zero_gadget: IsZeroWordGadget>>, + original_eq_value_gadget: IsEqualWordGadget>, Word>>, + prev_eq_value_gadget: IsEqualWordGadget>, Word>>, + original_eq_prev_gadget: IsEqualWordGadget>, Word>>, } impl SstoreTxRefundGadget { - pub(crate) fn construct( + pub(crate) fn construct>( cb: &mut EVMConstraintBuilder, - tx_refund_old: Cell, - value: Cell, - value_prev: Cell, - original_value: Cell, + tx_refund_old: U64Cell, + value: T, + value_prev: T, + original_value: T, ) -> Self { - let value_prev_is_zero_gadget = IsZeroGadget::construct(cb, value_prev.expr()); - let value_is_zero_gadget = IsZeroGadget::construct(cb, value.expr()); - let original_is_zero_gadget = IsZeroGadget::construct(cb, original_value.expr()); + let value_prev_is_zero_gadget = IsZeroWordGadget::construct(cb, &value_prev.to_word()); + let value_is_zero_gadget = IsZeroWordGadget::construct(cb, &value.to_word()); + let original_is_zero_gadget = IsZeroWordGadget::construct(cb, &original_value.to_word()); let original_eq_value_gadget = - IsEqualGadget::construct(cb, original_value.expr(), value.expr()); - let prev_eq_value_gadget = IsEqualGadget::construct(cb, value_prev.expr(), value.expr()); + IsEqualWordGadget::construct(cb, &original_value.to_word(), &value.to_word()); + let prev_eq_value_gadget = + IsEqualWordGadget::construct(cb, &value_prev.to_word(), &value.to_word()); let original_eq_prev_gadget = - IsEqualGadget::construct(cb, original_value.expr(), value_prev.expr()); + IsEqualWordGadget::construct(cb, &original_value.to_word(), &value_prev.to_word()); let value_prev_is_zero = value_prev_is_zero_gadget.expr(); let value_is_zero = value_is_zero_gadget.expr(); @@ -294,9 +285,6 @@ impl SstoreTxRefundGadget { - recreate_slot * (GasCost::SSTORE_CLEARS_SCHEDULE.expr()); Self { - value, - value_prev, - original_value, tx_refund_old, tx_refund_new, value_prev_is_zero_gadget, @@ -325,38 +313,30 @@ impl SstoreTxRefundGadget { original_value: eth_types::Word, ) -> Result<(), Error> { self.tx_refund_old - .assign(region, offset, Value::known(F::from(tx_refund_old)))?; - 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))?; + .assign(region, offset, Some(tx_refund_old.to_le_bytes()))?; self.value_prev_is_zero_gadget - .assign_value(region, offset, region.word_rlc(value_prev))?; + .assign(region, offset, Word::from(value_prev))?; self.value_is_zero_gadget - .assign_value(region, offset, region.word_rlc(value))?; - self.original_is_zero_gadget.assign_value( - region, - offset, - region.word_rlc(original_value), - )?; - self.original_eq_value_gadget.assign_value( + .assign(region, offset, Word::from(value))?; + self.original_is_zero_gadget + .assign(region, offset, Word::from(original_value))?; + self.original_eq_value_gadget.assign( region, offset, - region.word_rlc(original_value), - region.word_rlc(value), + Word::from(original_value), + Word::from(value), )?; - self.prev_eq_value_gadget.assign_value( + self.prev_eq_value_gadget.assign( region, offset, - region.word_rlc(value_prev), - region.word_rlc(value), + Word::from(value_prev), + Word::from(value), )?; - self.original_eq_prev_gadget.assign_value( + self.original_eq_prev_gadget.assign( region, offset, - region.word_rlc(original_value), - region.word_rlc(value_prev), + Word::from(original_value), + Word::from(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/stop.rs b/zkevm-circuits/src/evm_circuit/execution/stop.rs index 5b635381c6..fca4b8b194 100644 --- a/zkevm-circuits/src/evm_circuit/execution/stop.rs +++ b/zkevm-circuits/src/evm_circuit/execution/stop.rs @@ -14,7 +14,10 @@ use crate::{ witness::{Block, Call, ExecStep, Transaction}, }, table::CallContextFieldTag, - util::Expr, + util::{ + word::{Word, WordExpr}, + Expr, + }, }; use bus_mapping::evm::OpcodeId; use eth_types::{Field, ToWord}; @@ -35,7 +38,7 @@ impl ExecutionGadget for StopGadget { fn configure(cb: &mut EVMConstraintBuilder) -> Self { let code_length = cb.query_cell(); - cb.bytecode_length(cb.curr.state.code_hash.expr(), code_length.expr()); + cb.bytecode_length_word(cb.curr.state.code_hash.to_word(), code_length.expr()); let is_out_of_range = IsZeroGadget::construct( cb, code_length.expr() - cb.curr.state.program_counter.expr(), @@ -54,7 +57,7 @@ impl ExecutionGadget for StopGadget { ); // Call ends with STOP must be successful - cb.call_context_lookup(false.expr(), None, CallContextFieldTag::IsSuccess, 1.expr()); + cb.call_context_lookup_read(None, CallContextFieldTag::IsSuccess, Word::one()); let is_to_end_tx = cb.next.execution_state_selector([ExecutionState::EndTx]); cb.require_equal( diff --git a/zkevm-circuits/src/evm_circuit/execution/swap.rs b/zkevm-circuits/src/evm_circuit/execution/swap.rs index 7238aa5833..17e893a03b 100644 --- a/zkevm-circuits/src/evm_circuit/execution/swap.rs +++ b/zkevm-circuits/src/evm_circuit/execution/swap.rs @@ -5,11 +5,14 @@ use crate::{ util::{ common_gadget::SameContextGadget, constraint_builder::{EVMConstraintBuilder, StepStateTransition, Transition::Delta}, - CachedRegion, Cell, + CachedRegion, }, witness::{Block, Call, ExecStep, Transaction}, }, - util::Expr, + util::{ + word::{WordCell, WordExpr}, + Expr, + }, }; use eth_types::{evm_types::OpcodeId, Field}; use halo2_proofs::plonk::Error; @@ -17,7 +20,7 @@ use halo2_proofs::plonk::Error; #[derive(Clone, Debug)] pub(crate) struct SwapGadget { same_context: SameContextGadget, - phase2_values: [Cell; 2], + values: [WordCell; 2], } impl ExecutionGadget for SwapGadget { @@ -28,20 +31,20 @@ impl ExecutionGadget for SwapGadget { fn configure(cb: &mut EVMConstraintBuilder) -> Self { let opcode = cb.query_cell(); - let phase2_values = [cb.query_cell_phase2(), cb.query_cell_phase2()]; + let values = [cb.query_word_unchecked(), cb.query_word_unchecked()]; // 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(), phase2_values[0].expr()); + cb.stack_lookup_word(false.expr(), swap_offset.clone(), values[0].to_word()); // Peek the value at the top of the stack - cb.stack_lookup(false.expr(), 0.expr(), phase2_values[1].expr()); + cb.stack_lookup_word(false.expr(), 0.expr(), values[1].to_word()); // Write the value previously at the top of the stack to `swap_offset` - cb.stack_lookup(true.expr(), swap_offset, phase2_values[1].expr()); + cb.stack_lookup_word(true.expr(), swap_offset, values[1].to_word()); // Write the value previously at `swap_offset` to the top of the stack - cb.stack_lookup(true.expr(), 0.expr(), phase2_values[0].expr()); + cb.stack_lookup_word(true.expr(), 0.expr(), values[0].to_word()); // State transition let step_state_transition = StepStateTransition { @@ -54,7 +57,7 @@ impl ExecutionGadget for SwapGadget { Self { same_context, - phase2_values, + values, } } @@ -69,12 +72,12 @@ impl ExecutionGadget for SwapGadget { ) -> Result<(), Error> { self.same_context.assign_exec_step(region, offset, step)?; - for (cell, value) in self.phase2_values.iter().zip( + for (cell, value) in self.values.iter().zip( [0, 1] .map(|index| block.get_rws(step, index).stack_value()) .iter(), ) { - cell.assign(region, offset, region.word_rlc(*value))?; + cell.assign_u256(region, offset, *value)?; } Ok(()) diff --git a/zkevm-circuits/src/evm_circuit/param.rs b/zkevm-circuits/src/evm_circuit/param.rs index e21530bb9c..ee9f10fbb1 100644 --- a/zkevm-circuits/src/evm_circuit/param.rs +++ b/zkevm-circuits/src/evm_circuit/param.rs @@ -80,6 +80,9 @@ pub(crate) const MAX_N_BYTES_INTEGER: usize = 31; // Number of bytes an EVM word has. pub(crate) const N_BYTES_WORD: usize = 32; +// Number of bytes an half EVM word has. +pub(crate) const N_BYTES_HALF_WORD: usize = N_BYTES_WORD / 2; + // Number of bytes an u64 has. pub(crate) const N_BYTES_U64: usize = 8; diff --git a/zkevm-circuits/src/evm_circuit/step.rs b/zkevm-circuits/src/evm_circuit/step.rs index c9081600a8..3f1cfdd7fd 100644 --- a/zkevm-circuits/src/evm_circuit/step.rs +++ b/zkevm-circuits/src/evm_circuit/step.rs @@ -15,7 +15,7 @@ use bus_mapping::{ error::{DepthError, ExecError, InsufficientBalanceError, NonceUintOverflowError, OogError}, evm::OpcodeId, }; -use eth_types::{evm_unimplemented, Field}; +use eth_types::{evm_unimplemented, Field, ToWord}; use halo2_proofs::{ circuit::Value, plonk::{Advice, Column, ConstraintSystem, Error, Expression}, @@ -66,9 +66,7 @@ pub enum ExecutionState { RETURNDATACOPY, EXTCODEHASH, BLOCKHASH, - BLOCKCTXU64, // TIMESTAMP, NUMBER, GASLIMIT - BLOCKCTXU160, // COINBASE - BLOCKCTXU256, // DIFFICULTY, BASEFEE + BLOCKCTX, // TIMESTAMP, NUMBER, GASLIMIT, COINBASE, DIFFICULTY, BASEFEE CHAINID, SELFBALANCE, POP, @@ -239,11 +237,12 @@ impl From<&ExecStep> for ExecutionState { OpcodeId::EXTCODEHASH => ExecutionState::EXTCODEHASH, OpcodeId::EXTCODESIZE => ExecutionState::EXTCODESIZE, OpcodeId::BLOCKHASH => ExecutionState::BLOCKHASH, - OpcodeId::TIMESTAMP | OpcodeId::NUMBER | OpcodeId::GASLIMIT => { - ExecutionState::BLOCKCTXU64 - } - OpcodeId::COINBASE => ExecutionState::BLOCKCTXU160, - OpcodeId::DIFFICULTY | OpcodeId::BASEFEE => ExecutionState::BLOCKCTXU256, + OpcodeId::TIMESTAMP + | OpcodeId::NUMBER + | OpcodeId::GASLIMIT + | OpcodeId::COINBASE + | OpcodeId::DIFFICULTY + | OpcodeId::BASEFEE => ExecutionState::BLOCKCTX, OpcodeId::GAS => ExecutionState::GAS, OpcodeId::SAR => ExecutionState::SAR, OpcodeId::SELFBALANCE => ExecutionState::SELFBALANCE, @@ -379,9 +378,14 @@ impl ExecutionState { Self::RETURNDATACOPY => vec![OpcodeId::RETURNDATACOPY], Self::EXTCODEHASH => vec![OpcodeId::EXTCODEHASH], Self::BLOCKHASH => vec![OpcodeId::BLOCKHASH], - Self::BLOCKCTXU64 => vec![OpcodeId::TIMESTAMP, OpcodeId::NUMBER, OpcodeId::GASLIMIT], - Self::BLOCKCTXU160 => vec![OpcodeId::COINBASE], - Self::BLOCKCTXU256 => vec![OpcodeId::DIFFICULTY, OpcodeId::BASEFEE], + Self::BLOCKCTX => vec![ + OpcodeId::TIMESTAMP, + OpcodeId::NUMBER, + OpcodeId::GASLIMIT, + OpcodeId::COINBASE, + OpcodeId::DIFFICULTY, + OpcodeId::BASEFEE, + ], Self::CHAINID => vec![OpcodeId::CHAINID], Self::SELFBALANCE => vec![OpcodeId::SELFBALANCE], Self::POP => vec![OpcodeId::POP], @@ -738,7 +742,7 @@ impl Step { )?; self.state .code_hash - .assign(region, offset, Some(call.code_hash.to_fixed_bytes()))?; + .assign_u256(region, offset, call.code_hash.to_word())?; self.state .program_counter .assign(region, offset, Value::known(F::from(step.pc)))?; diff --git a/zkevm-circuits/src/evm_circuit/table.rs b/zkevm-circuits/src/evm_circuit/table.rs index 0a5557f083..3ceb37d95f 100644 --- a/zkevm-circuits/src/evm_circuit/table.rs +++ b/zkevm-circuits/src/evm_circuit/table.rs @@ -141,8 +141,7 @@ pub struct RwValues { pub storage_key: Word>, pub value: Word>, pub value_prev: Word>, - pub aux1: Expression, - pub aux2: Expression, + pub init_val: Word>, } impl RwValues { @@ -154,8 +153,7 @@ impl RwValues { storage_key: Word>, value: Word>, value_prev: Word>, - aux1: Expression, - aux2: Expression, + init_val: Word>, ) -> Self { Self { id, @@ -164,8 +162,7 @@ impl RwValues { storage_key, value, value_prev, - aux1, - aux2, + init_val, } } } @@ -237,11 +234,11 @@ pub(crate) enum Lookup { /// Whether the row is the first row of the copy event. is_first: Expression, /// The source ID for the copy event. - src_id: Expression, + src_id: Word>, /// The source tag for the copy event. src_tag: Expression, /// The destination ID for the copy event. - dst_id: Expression, + dst_id: Word>, /// The destination tag for the copy event. dst_tag: Expression, /// The source address where bytes are copied from. @@ -336,8 +333,8 @@ impl Lookup { values.value.hi(), values.value_prev.lo(), values.value_prev.hi(), - values.aux1.clone(), - values.aux2.clone(), + values.init_val.lo(), + values.init_val.hi(), ], Self::Bytecode { hash, @@ -373,9 +370,11 @@ impl Lookup { rwc_inc, } => vec![ is_first.clone(), - src_id.clone(), + src_id.lo(), + src_id.hi(), src_tag.clone(), - dst_id.clone(), + dst_id.lo(), + dst_id.hi(), dst_tag.clone(), src_addr.clone(), src_addr_end.clone(), diff --git a/zkevm-circuits/src/evm_circuit/util.rs b/zkevm-circuits/src/evm_circuit/util.rs index 9fa7abdaf4..672c796087 100644 --- a/zkevm-circuits/src/evm_circuit/util.rs +++ b/zkevm-circuits/src/evm_circuit/util.rs @@ -1,6 +1,6 @@ pub use crate::util::{ query_expression, - word::{Word as WordNew, WordExpr, WordLegacy as Word}, + word::{Word, WordExpr}, Challenges, Expr, }; use crate::{ @@ -10,6 +10,7 @@ use crate::{ }, table::Table, }, + util::int_decomposition::IntDecomposition, witness::{Block, ExecStep, Rw, RwMap}, }; use bus_mapping::state_db::CodeDB; @@ -36,7 +37,7 @@ pub use gadgets::util::{and, not, or, select, sum}; use super::param::{N_BYTES_ACCOUNT_ADDRESS, N_BYTES_U64}; #[derive(Clone, Debug)] -pub(crate) struct Cell { +pub struct Cell { // expression for constraint expression: Expression, column: Column, @@ -210,12 +211,17 @@ impl<'r, 'b, F: Field> CachedRegion<'r, 'b, F> { self.word_rlc(CodeDB::empty_code_hash().to_word()) } + #[deprecated(note = "in fav of code_hash_word")] pub fn code_hash(&self, n: U256) -> Value { self.challenges .evm_word() .map(|r| rlc::value(&n.to_le_bytes(), r)) } + pub fn code_hash_word(&self, n: U256) -> Word> { + Word::from(n).into_value() + } + /// Constrains a cell to have a constant value. /// /// Returns an error if the cell is in a column where equality has not been @@ -485,6 +491,7 @@ pub struct RandomLinearCombination { impl RandomLinearCombination { const N_BYTES: usize = N; + /// XXX for randomness 256.expr(), consider using IntDecomposition instead pub(crate) fn new(cells: [Cell; N], randomness: Expression) -> Self { Self { expression: rlc::expr(&cells.clone().map(|cell| cell.expr()), randomness), @@ -516,44 +523,11 @@ impl Expr for RandomLinearCombination { } } -pub(crate) type MemoryAddress = RandomLinearCombination; +pub(crate) type MemoryAddress = IntDecomposition; -impl WordExpr for MemoryAddress { - fn to_word(&self) -> WordNew> { - WordNew::from_lo_unchecked(self.expr()) - } -} - -pub(crate) type AccountAddress = RandomLinearCombination; - -impl WordExpr for AccountAddress { - fn to_word(&self) -> WordNew> { - WordNew::new([ - rlc::expr( - &self.cells[0..16] - .iter() - .map(|cell| cell.expr()) - .collect_vec(), - 256.expr(), - ), - rlc::expr( - &self.cells[16..] - .iter() - .map(|cell| cell.expr()) - .collect_vec(), - 256.expr(), - ), - ]) - } -} +pub(crate) type AccountAddress = IntDecomposition; -pub(crate) type U64Cell = RandomLinearCombination; - -impl WordExpr for U64Cell { - fn to_word(&self) -> WordNew> { - WordNew::from_lo_unchecked(self.expr()) - } -} +pub(crate) type U64Cell = IntDecomposition; /// Decodes a field element from its byte representation in little endian order pub(crate) mod from_bytes { @@ -677,6 +651,15 @@ pub(crate) fn is_precompiled(address: &Address) -> bool { address.0[0..19] == [0u8; 19] && (1..=9).contains(&address.0[19]) } +const BASE_128_BYTES: [u8; 32] = [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +]; + +/// convert address (h160) to single expression. +pub fn address_word_to_expr(address: Word>) -> Expression { + address.lo() + address.hi() * Expression::Constant(F::from_repr(BASE_128_BYTES).unwrap()) +} + /// Helper struct to read rw operations from a step sequentially. pub(crate) struct StepRws<'a> { rws: &'a RwMap, diff --git a/zkevm-circuits/src/evm_circuit/util/common_gadget.rs b/zkevm-circuits/src/evm_circuit/util/common_gadget.rs index 338c1a7214..95986b73db 100644 --- a/zkevm-circuits/src/evm_circuit/util/common_gadget.rs +++ b/zkevm-circuits/src/evm_circuit/util/common_gadget.rs @@ -7,7 +7,7 @@ use super::{ }; use crate::{ evm_circuit::{ - param::{N_BYTES_ACCOUNT_ADDRESS, N_BYTES_GAS, N_BYTES_MEMORY_WORD_SIZE}, + param::{N_BYTES_GAS, N_BYTES_MEMORY_WORD_SIZE}, step::ExecutionState, table::{FixedTableTag, Lookup}, util::{ @@ -21,7 +21,7 @@ use crate::{ }, table::{AccountFieldTag, CallContextFieldTag}, util::{ - word::{Word, Word32Cell, WordCell, WordExpr}, + word::{Word, Word32, Word32Cell, WordCell, WordExpr}, Expr, }, witness::{Block, Call, ExecStep}, @@ -118,10 +118,15 @@ impl RestoreContextGadget { ) -> Self { // Read caller's context for restore let caller_id = cb.call_context(None, CallContextFieldTag::CallerId); - let [caller_is_root, caller_is_create, caller_program_counter, caller_stack_pointer, caller_gas_left, caller_memory_word_size, caller_reversible_write_counter] = + let [caller_is_root, caller_is_create] = + [CallContextFieldTag::IsRoot, CallContextFieldTag::IsCreate] + .map(|field_tag| cb.call_context(Some(caller_id.expr()), field_tag)); + + let caller_code_hash = + cb.call_context_read_as_word(Some(caller_id.expr()), CallContextFieldTag::CodeHash); + + let [caller_program_counter, caller_stack_pointer, caller_gas_left, caller_memory_word_size, caller_reversible_write_counter] = [ - CallContextFieldTag::IsRoot, - CallContextFieldTag::IsCreate, CallContextFieldTag::ProgramCounter, CallContextFieldTag::StackPointer, CallContextFieldTag::GasLeft, @@ -130,9 +135,6 @@ impl RestoreContextGadget { ] .map(|field_tag| cb.call_context(Some(caller_id.expr()), field_tag)); - let caller_code_hash = - cb.call_context_read_as_word(Some(caller_id.expr()), CallContextFieldTag::CodeHash); - // Update caller's last callee information // EIP-211 CREATE/CREATE2 call successful case should set RETURNDATASIZE = 0 let is_call_create_and_success_expr = cb.curr.state.is_create.expr() * is_success.clone(); @@ -159,7 +161,7 @@ impl RestoreContextGadget { ), ] { // TODO review and assure range check - cb.call_context_lookup_write_unchecked( + cb.call_context_lookup_write( Some(caller_id.expr()), field_tag, Word::from_lo_unchecked(value), @@ -197,7 +199,7 @@ impl RestoreContextGadget { call_id: To(caller_id.expr()), is_root: To(caller_is_root.expr()), is_create: To(caller_is_create.expr()), - code_hash: To(caller_code_hash.expr()), + code_hash: To(caller_code_hash.to_word()), program_counter: To(caller_program_counter.expr()), stack_pointer: To(caller_stack_pointer.expr()), gas_left: To(gas_left), @@ -261,7 +263,7 @@ impl RestoreContextGadget { } self.caller_code_hash - .assign(region, offset, Some(caller_code_hash.to_le_bytes()))?; + .assign_u256(region, offset, caller_code_hash)?; Ok(()) } @@ -277,7 +279,7 @@ impl { pub(crate) fn construct( cb: &mut EVMConstraintBuilder, - address: Expression, + address: Word>, updates: Vec>, reversion_info: Option<&mut ReversionInfo>, ) -> Self { @@ -286,13 +288,13 @@ impl let balance_addend = cb.query_word32(); let balance_sum = cb.query_word32(); - let [value, value_prev] = if INCREASE { - [balance_sum.word_expr(), balance_addend.word_expr()] + let [value, value_prev]: [Word32>; 2] = if INCREASE { + [balance_sum.to_word_n(), balance_addend.to_word_n()] } else { - [balance_addend.word_expr(), balance_sum.word_expr()] + [balance_addend.to_word_n(), balance_sum.to_word_n()] }; - let add_words = AddWordsGadget::construct_new( + let add_words = AddWordsGadget::construct( cb, std::iter::once(balance_addend) .chain(updates.to_vec()) @@ -371,23 +373,9 @@ pub(crate) struct TransferWithGasFeeGadget { impl TransferWithGasFeeGadget { #[allow(clippy::too_many_arguments)] pub(crate) fn construct( - _cb: &mut EVMConstraintBuilder, - _sender_address: Expression, - _receiver_address: Expression, - _receiver_exists: Expression, - _must_create: Expression, - _value: Word, - _gas_fee: Word, - _reversion_info: &mut ReversionInfo, - ) -> Self { - todo!() - } - - #[allow(clippy::too_many_arguments)] - pub(crate) fn construct_new( cb: &mut EVMConstraintBuilder, - sender_address: Expression, - receiver_address: Expression, + sender_address: Word>, + receiver_address: Word>, receiver_exists: Expression, must_create: Expression, value: Word32Cell, @@ -395,8 +383,8 @@ impl TransferWithGasFeeGadget { reversion_info: &mut ReversionInfo, ) -> Self { let sender_sub_fee = - UpdateBalanceGadget::construct(cb, sender_address.expr(), vec![gas_fee], None); - let value_is_zero = IsZeroWordGadget::construct(cb, value.clone()); + UpdateBalanceGadget::construct(cb, sender_address.to_word(), vec![gas_fee], None); + let value_is_zero = IsZeroWordGadget::construct(cb, &value); // If receiver doesn't exist, create it cb.condition( or::expr([ @@ -519,14 +507,14 @@ pub(crate) struct TransferGadget { impl TransferGadget { pub(crate) fn construct( cb: &mut EVMConstraintBuilder, - sender_address: Expression, - receiver_address: Expression, + sender_address: Word>, + receiver_address: Word>, receiver_exists: Expression, must_create: Expression, value: Word32Cell, reversion_info: &mut ReversionInfo, ) -> Self { - let value_is_zero = IsZeroWordGadget::construct(cb, value.clone()); + let value_is_zero = IsZeroWordGadget::construct(cb, &value); // If receiver doesn't exist, create it cb.condition( or::expr([ @@ -622,7 +610,7 @@ pub(crate) struct CommonCallGadget { pub gas: Word32Cell, pub gas_is_u64: IsZeroGadget, - pub callee_address: AccountAddress, + pub callee_address_word: AccountAddress, pub value: Word32Cell, pub cd_address: MemoryAddressGadget, pub rd_address: MemoryAddressGadget, @@ -654,10 +642,10 @@ impl CommonCallGadget let gas_word = cb.query_word32(); let callee_address_word = cb.query_account_address(); let value = cb.query_word32(); - let cd_offset = cb.query_word32(); - let cd_length = cb.query_word32(); - let rd_offset = cb.query_word32(); - let rd_length = cb.query_word32(); + let cd_offset = cb.query_word_unchecked(); + let cd_length = cb.query_memory_address(); + let rd_offset = cb.query_word_unchecked(); + let rd_length = cb.query_memory_address(); let is_success = cb.query_bool(); // Lookup values from stack @@ -687,13 +675,13 @@ impl CommonCallGadget // Recomposition of random linear combination to integer let gas_is_u64 = IsZeroGadget::construct(cb, sum::expr(&gas_word.limbs[N_BYTES_GAS..])); - let cd_address = MemoryAddressGadget::construct_new(cb, cd_offset, cd_length); - let rd_address = MemoryAddressGadget::construct_new(cb, rd_offset, rd_length); + let cd_address = MemoryAddressGadget::construct(cb, cd_offset, cd_length); + let rd_address = MemoryAddressGadget::construct(cb, rd_offset, rd_length); let memory_expansion = MemoryExpansionGadget::construct(cb, [cd_address.address(), rd_address.address()]); // construct common gadget - let value_is_zero = IsZeroWordGadget::construct(cb, value.clone()); + let value_is_zero = IsZeroWordGadget::construct(cb, &value); let has_value = select::expr( is_delegatecall.expr() + is_staticcall.expr(), 0.expr(), @@ -702,17 +690,17 @@ impl CommonCallGadget let callee_code_hash = cb.query_word_unchecked(); cb.account_read_word( - callee_address_word.expr(), + callee_address_word.to_word(), AccountFieldTag::CodeHash, callee_code_hash.to_word(), ); let is_empty_code_hash = - IsEqualWordGadget::construct(cb, callee_code_hash.clone(), cb.empty_code_hash_word()); - let callee_not_exists = IsZeroWordGadget::construct(cb, callee_code_hash.clone()); + IsEqualWordGadget::construct(cb, &callee_code_hash, &cb.empty_code_hash_word()); + let callee_not_exists = IsZeroWordGadget::construct(cb, &callee_code_hash); Self { is_success, - callee_address: callee_address_word, + callee_address_word, gas: gas_word, gas_is_u64, value, @@ -727,8 +715,8 @@ impl CommonCallGadget } } - pub fn callee_address_expr(&self) -> Expression { - self.callee_address.expr() + pub fn callee_address_word(&self) -> Word> { + self.callee_address_word.to_word() } pub fn gas_expr(&self) -> Expression { @@ -767,16 +755,10 @@ impl CommonCallGadget memory_word_size: u64, callee_code_hash: U256, ) -> Result { - self.gas.assign(region, offset, Some(gas.to_le_bytes()))?; - self.callee_address.assign( - region, - offset, - callee_address.to_le_bytes()[0..N_BYTES_ACCOUNT_ADDRESS] - .try_into() - .ok(), - )?; - self.value - .assign(region, offset, Some(value.to_le_bytes()))?; + self.gas.assign_u256(region, offset, gas)?; + self.callee_address_word + .assign_u256(region, offset, callee_address)?; + self.value.assign_u256(region, offset, value)?; if IS_SUCCESS_CALL { self.is_success .assign(region, offset, Value::known(F::from(is_success.low_u64())))?; @@ -802,7 +784,7 @@ impl CommonCallGadget self.value_is_zero .assign(region, offset, Word::from(value))?; self.callee_code_hash - .assign(region, offset, Some(callee_code_hash.to_le_bytes()))?; + .assign_u256(region, offset, callee_code_hash)?; self.is_empty_code_hash.assign_value( region, offset, @@ -869,39 +851,25 @@ impl SloadGasGadget { } #[derive(Clone, Debug)] -pub(crate) struct SstoreGasGadget { - value: WordCell, - value_prev: WordCell, - original_value: WordCell, +pub(crate) struct SstoreGasGadget { is_warm: Cell, gas_cost: Expression, - value_eq_prev: IsEqualWordGadget, WordCell>, - original_eq_prev: IsEqualWordGadget, WordCell>, - original_is_zero: IsZeroWordGadget>, + value_eq_prev: IsEqualWordGadget, + original_eq_prev: IsEqualWordGadget, + original_is_zero: IsZeroWordGadget, } -impl SstoreGasGadget { +impl + Clone> SstoreGasGadget { pub(crate) fn construct( - _cb: &mut EVMConstraintBuilder, - _value: Cell, - _value_prev: Cell, - _original_value: Cell, - _is_warm: Cell, - ) -> Self { - todo!() - } - - pub(crate) fn construct_new( cb: &mut EVMConstraintBuilder, - value: WordCell, - value_prev: WordCell, - original_value: WordCell, is_warm: Cell, + value: T, + value_prev: T, + original_value: T, ) -> Self { - let value_eq_prev = IsEqualWordGadget::construct(cb, value.clone(), value_prev.clone()); - let original_eq_prev = - IsEqualWordGadget::construct(cb, original_value.clone(), value_prev.clone()); - let original_is_zero = IsZeroWordGadget::construct(cb, original_value.clone()); + let value_eq_prev = IsEqualWordGadget::construct(cb, &value, &value_prev); + let original_eq_prev = IsEqualWordGadget::construct(cb, &original_value, &value_prev); + let original_is_zero = IsZeroWordGadget::construct(cb, &original_value); let warm_case_gas = select::expr( value_eq_prev.expr(), GasCost::WARM_ACCESS.expr(), @@ -922,9 +890,6 @@ impl SstoreGasGadget { ); Self { - value, - value_prev, - original_value, is_warm, gas_cost, value_eq_prev, @@ -946,12 +911,6 @@ impl SstoreGasGadget { original_value: eth_types::Word, is_warm: bool, ) -> Result<(), Error> { - self.value - .assign(region, offset, Some(value.to_le_bytes()))?; - self.value_prev - .assign(region, offset, Some(value_prev.to_le_bytes()))?; - self.original_value - .assign(region, offset, Some(original_value.to_le_bytes()))?; self.is_warm .assign(region, offset, Value::known(F::from(is_warm as u64)))?; self.value_eq_prev.assign_value( @@ -1089,10 +1048,10 @@ impl CommonErrorGadget { step: &ExecStep, rw_offset: usize, ) -> Result { - self.rw_counter_end_of_reversion.assign_lo( + self.rw_counter_end_of_reversion.assign_u64( region, offset, - Value::known(F::from(call.rw_counter_end_of_reversion as u64)), + call.rw_counter_end_of_reversion as u64, )?; self.restore_context .assign(region, offset, block, call, step, rw_offset)?; @@ -1147,11 +1106,6 @@ impl WordByteCapGadget { self.lt_cap.expr() } - #[deprecated(note = "in fav of original_word_new")] - pub(crate) fn original_word(&self) -> Expression { - self.word.original.limbs[0].expr() - } - pub(crate) fn original_word_new(&self) -> Word32Cell { self.word.original.clone() } @@ -1196,8 +1150,7 @@ impl WordByteRangeGadget { offset: usize, original: U256, ) -> Result { - self.original - .assign(region, offset, Some(original.to_le_bytes()))?; + self.original.assign_u256(region, offset, original)?; let overflow_hi = original.to_le_bytes()[VALID_BYTES..] .iter() @@ -1216,11 +1169,6 @@ impl WordByteRangeGadget { self.original.to_word() } - #[deprecated(note = "in fav of original")] - pub(crate) fn original_word(&self) -> Expression { - todo!() - } - pub(crate) fn valid_value(&self) -> Expression { from_bytes::expr(&self.original.limbs[..VALID_BYTES]) } diff --git a/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs b/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs index d9fe5cf01c..65ce6106ca 100644 --- a/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs +++ b/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs @@ -11,9 +11,7 @@ use crate::{ }, util::{ build_tx_log_expression, - word::{ - Word, Word16, Word32, Word32Cell, Word4, WordCell, WordExpr, WordLegacy, WordLimbs, - }, + word::{Word, Word16, Word32, Word32Cell, Word4, WordCell, WordExpr, WordLimbs}, Challenges, Expr, }, }; @@ -29,7 +27,8 @@ use halo2_proofs::{ }; use super::{ - rlc, AccountAddress, CachedRegion, CellType, MemoryAddress, StoredExpression, U64Cell, + address_word_to_expr, rlc, AccountAddress, CachedRegion, CellType, MemoryAddress, + StoredExpression, U64Cell, }; // Max degree allowed in all expressions passing through the ConstraintBuilder. @@ -58,7 +57,7 @@ pub(crate) struct StepStateTransition { pub(crate) call_id: Transition>, pub(crate) is_root: Transition>, pub(crate) is_create: Transition>, - pub(crate) code_hash: Transition>, + pub(crate) code_hash: Transition>>, pub(crate) program_counter: Transition>, pub(crate) stack_pointer: Transition>, pub(crate) gas_left: Transition>, @@ -421,11 +420,6 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { self.query_cell_with_type(CellType::LookupByte) } - #[deprecated(note = "query_word* are favored")] - pub(crate) fn query_word_rlc(&mut self) -> RandomLinearCombination { - RandomLinearCombination::::new(self.query_bytes(), self.challenges.evm_word()) - } - // default query_word is 2 limbs. Each limb is not guaranteed to be 128 bits. pub fn query_word_unchecked(&mut self) -> WordCell { Word::new( @@ -483,15 +477,15 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { } pub(crate) fn query_u64(&mut self) -> U64Cell { - U64Cell::new(self.query_bytes(), 256u64.expr()) + U64Cell::new(self.query_bytes()) } pub(crate) fn query_account_address(&mut self) -> AccountAddress { - AccountAddress::::new(self.query_bytes(), 256u64.expr()) + AccountAddress::::new(self.query_bytes()) } pub(crate) fn query_memory_address(&mut self) -> MemoryAddress { - MemoryAddress::::new(self.query_bytes(), 256u64.expr()) + MemoryAddress::::new(self.query_bytes()) } pub(crate) fn query_bytes(&mut self) -> [Cell; N] { @@ -601,7 +595,7 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { Transition::To(to) => self.require_equal_word( concat!("State transition (to) constraint of ", stringify!($name)), self.next.state.$name.to_word(), - Word::from_lo_unchecked(to), + to, ), _ => {} } @@ -686,18 +680,6 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { ); } - // Bytecode table - #[deprecated(note = "in fav of bytecode_lookup_word")] - pub(crate) fn bytecode_lookup( - &mut self, - code_hash: Expression, - index: Expression, - is_code: Expression, - value: Expression, - ) { - self.bytecode_lookup_word(Word::from_lo_unchecked(code_hash), index, is_code, value) - } - pub(crate) fn bytecode_lookup_word( &mut self, code_hash: Word>, @@ -717,11 +699,6 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { ) } - #[deprecated(note = "in fav of bytecode_length_word")] - pub(crate) fn bytecode_length(&mut self, code_hash: Expression, value: Expression) { - self.bytecode_length_word(Word::from_lo_unchecked(code_hash), value) - } - pub(crate) fn bytecode_length_word( &mut self, code_hash: Word>, @@ -752,18 +729,6 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { self.tx_context_lookup_word(id, field_tag, index, Word::from_lo_unchecked(cell.expr())); cell } - #[deprecated(note = "tx_context_as_word32 is favored")] - pub(crate) fn tx_context_as_word( - &mut self, - id: Expression, - field_tag: TxContextFieldTag, - index: Option>, - ) -> WordLegacy { - let word = self.query_word_rlc(); - self.tx_context_lookup_word(id, field_tag, index, word.to_word()); - word - } - pub(crate) fn tx_context_as_word32( &mut self, id: Expression, @@ -775,16 +740,15 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { word } - #[deprecated(note = "tx_context_lookup_word is favored")] - pub(crate) fn tx_context_lookup( + pub(crate) fn tx_context_as_word( &mut self, id: Expression, field_tag: TxContextFieldTag, index: Option>, - value: Expression, - ) { - let value = Word::from_lo_unchecked(value); - self.tx_context_lookup_word(id, field_tag, index, value) + ) -> WordCell { + let word = self.query_word_unchecked(); + self.tx_context_lookup_word(id, field_tag, index, word.to_word()); + word } pub(crate) fn tx_context_lookup_word( @@ -806,16 +770,6 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { } // block - #[deprecated(note = "block_lookup_word is favored")] - pub(crate) fn block_lookup( - &mut self, - tag: Expression, - number: Option>, - val: Expression, - ) { - self.block_lookup_word(tag, number, Word::from_lo_unchecked(val)) - } - pub(crate) fn block_lookup_word( &mut self, tag: Expression, @@ -922,64 +876,35 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { } // Access list - - #[deprecated(note = "account_access_list_write_word is favored")] - pub(crate) fn account_access_list_write( + pub(crate) fn account_access_list_write_unchecked( &mut self, tx_id: Expression, - account_address: Expression, + account_address: Word>, value: Expression, value_prev: Expression, reversion_info: Option<&mut ReversionInfo>, - ) { - self.account_access_list_write_word( - tx_id, - account_address, - Word::from_lo_unchecked(value), - Word::from_lo_unchecked(value_prev), - reversion_info, - ) - } - - pub(crate) fn account_access_list_write_word( - &mut self, - tx_id: Expression, - account_address: Expression, - value: Word>, - value_prev: Word>, - reversion_info: Option<&mut ReversionInfo>, ) { self.reversible_write( "TxAccessListAccount write", Target::TxAccessListAccount, RwValues::new( tx_id, - account_address, + address_word_to_expr(account_address), 0.expr(), Word::zero(), - value, - value_prev, - 0.expr(), - 0.expr(), + Word::from_lo_unchecked(value), + Word::from_lo_unchecked(value_prev), + Word::zero(), ), reversion_info, ); } - #[deprecated(note = "account_access_list_read_word is favored")] + pub(crate) fn account_access_list_read( &mut self, tx_id: Expression, - account_address: Expression, + account_address: Word>, value: Expression, - ) { - self.account_access_list_read_word(tx_id, account_address, Word::from_lo_unchecked(value)); - } - - pub(crate) fn account_access_list_read_word( - &mut self, - tx_id: Expression, - account_address: Expression, - value: Word>, ) { self.rw_lookup( "account access list read", @@ -987,41 +912,19 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { Target::TxAccessListAccount, RwValues::new( tx_id, - account_address, + address_word_to_expr(account_address), 0.expr(), Word::zero(), - value.clone(), - value, - 0.expr(), - 0.expr(), + Word::from_lo_unchecked(value.clone()), + Word::from_lo_unchecked(value), + Word::zero(), ), ); } - - #[deprecated(note = "account_storage_access_list_write_word is favored")] - pub(crate) fn account_storage_access_list_write( - &mut self, - tx_id: Expression, - account_address: Expression, - storage_key: Expression, - value: Expression, - value_prev: Expression, - reversion_info: Option<&mut ReversionInfo>, - ) { - self.account_storage_access_list_write_word( - tx_id, - account_address, - Word::from_lo_unchecked(storage_key), - Word::from_lo_unchecked(value), - Word::from_lo_unchecked(value_prev), - reversion_info, - ) - } - pub(crate) fn account_storage_access_list_write_word( &mut self, tx_id: Expression, - account_address: Expression, + account_address: Word>, storage_key: Word>, value: Word>, value_prev: Word>, @@ -1032,37 +935,21 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { Target::TxAccessListAccountStorage, RwValues::new( tx_id, - account_address, + address_word_to_expr(account_address), 0.expr(), storage_key, value, value_prev, - 0.expr(), - 0.expr(), + Word::zero(), ), reversion_info, ); } - #[deprecated(note = "account_storage_access_list_read_word is favored")] - pub(crate) fn account_storage_access_list_read( - &mut self, - tx_id: Expression, - account_address: Expression, - storage_key: Expression, - value: Expression, - ) { - self.account_storage_access_list_read_word( - tx_id, - account_address, - Word::from_lo_unchecked(storage_key), - Word::from_lo_unchecked(value), - ); - } pub(crate) fn account_storage_access_list_read_word( &mut self, tx_id: Expression, - account_address: Expression, + account_address: Word>, storage_key: Word>, value: Word>, ) { @@ -1072,13 +959,12 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { Target::TxAccessListAccountStorage, RwValues::new( tx_id, - account_address, + address_word_to_expr(account_address), 0.expr(), storage_key, value.clone(), value, - 0.expr(), - 0.expr(), + Word::zero(), ), ); } @@ -1097,26 +983,10 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { Word::zero(), value.clone(), value, - 0.expr(), - 0.expr(), + Word::zero(), ), ); } - #[deprecated(note = "infav of tx_refund_write_word")] - pub(crate) fn tx_refund_write( - &mut self, - tx_id: Expression, - value: Expression, - value_prev: Expression, - reversion_info: Option<&mut ReversionInfo>, - ) { - self.tx_refund_write_word( - tx_id, - Word::from_lo_unchecked(value), - Word::from_lo_unchecked(value_prev), - reversion_info, - ) - } pub(crate) fn tx_refund_write_word( &mut self, @@ -1135,28 +1005,16 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { Word::zero(), value, value_prev, - 0.expr(), - 0.expr(), + Word::zero(), ), reversion_info, ); } // Account - - #[deprecated(note = "infav of account_read_word")] - pub(crate) fn account_read( - &mut self, - account_address: Expression, - field_tag: AccountFieldTag, - value: Expression, - ) { - self.account_read_word(account_address, field_tag, Word::from_lo_unchecked(value)); - } - pub(crate) fn account_read_word( &mut self, - account_address: Expression, + account_address: Word>, field_tag: AccountFieldTag, value: Word>, ) { @@ -1166,37 +1024,19 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { Target::Account, RwValues::new( 0.expr(), - account_address, + address_word_to_expr(account_address), field_tag.expr(), Word::zero(), value.clone(), value, - 0.expr(), - 0.expr(), + Word::zero(), ), ); } - #[deprecated(note = "infav of account_write_word")] - pub(crate) fn account_write( - &mut self, - account_address: Expression, - field_tag: AccountFieldTag, - value: Expression, - value_prev: Expression, - reversion_info: Option<&mut ReversionInfo>, - ) { - self.account_write_word( - account_address, - field_tag, - Word::from_lo_unchecked(value), - Word::from_lo_unchecked(value_prev), - reversion_info, - ) - } pub(crate) fn account_write_word( &mut self, - account_address: Expression, + account_address: Word>, field_tag: AccountFieldTag, value: Word>, value_prev: Word>, @@ -1207,45 +1047,25 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { Target::Account, RwValues::new( 0.expr(), - account_address, + address_word_to_expr(account_address), field_tag.expr(), Word::zero(), value, value_prev, - 0.expr(), - 0.expr(), + Word::zero(), ), reversion_info, ); } // Account Storage - - #[deprecated(note = "account_storage_read_word is preferred")] - pub(crate) fn account_storage_read( - &mut self, - account_address: Expression, - key: Expression, - value: Expression, - tx_id: Expression, - committed_value: Expression, - ) { - self.account_storage_read_word( - account_address, - Word::from_lo_unchecked(key), - Word::from_lo_unchecked(value), - tx_id, - committed_value, - ); - } - pub(crate) fn account_storage_read_word( &mut self, - account_address: Expression, + account_address: Word>, key: Word>, value: Word>, tx_id: Expression, - committed_value: Expression, + committed_value: Word>, ) { self.rw_lookup( "account_storage_read", @@ -1253,49 +1073,25 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { Target::Storage, RwValues::new( tx_id, - account_address, + address_word_to_expr(account_address), 0.expr(), key, value.clone(), value, - 0.expr(), committed_value, ), ); } - #[deprecated(note = "account_storage_write_word is preferred")] - #[allow(clippy::too_many_arguments)] - pub(crate) fn account_storage_write( - &mut self, - account_address: Expression, - key: Expression, - value: Expression, - value_prev: Expression, - tx_id: Expression, - committed_value: Expression, - reversion_info: Option<&mut ReversionInfo>, - ) { - self.account_storage_write_word( - account_address, - Word::from_lo_unchecked(key), - Word::from_lo_unchecked(value), - Word::from_lo_unchecked(value_prev), - tx_id, - committed_value, - reversion_info, - ); - } - #[allow(clippy::too_many_arguments)] pub(crate) fn account_storage_write_word( &mut self, - account_address: Expression, + account_address: Word>, key: Word>, value: Word>, value_prev: Word>, tx_id: Expression, - committed_value: Expression, + committed_value: Word>, reversion_info: Option<&mut ReversionInfo>, ) { self.reversible_write( @@ -1303,12 +1099,11 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { Target::Storage, RwValues::new( tx_id, - account_address, + address_word_to_expr(account_address), 0.expr(), key, value, value_prev, - 0.expr(), committed_value, ), reversion_info, @@ -1335,16 +1130,6 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { cell } - pub(crate) fn call_context_read( - &mut self, - call_id: Option>, - field_tag: CallContextFieldTag, - ) -> WordLegacy { - let word = self.query_word_rlc(); - self.call_context_lookup_read(call_id, field_tag, word.to_word()); - word - } - pub(crate) fn call_context_read_as_word( &mut self, call_id: Option>, @@ -1355,31 +1140,6 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { word } - #[deprecated(note = "call_context_lookup_read is favored")] - pub(crate) fn call_context_lookup( - &mut self, - is_write: Expression, - call_id: Option>, - field_tag: CallContextFieldTag, - value: Expression, - ) { - self.rw_lookup( - "CallContext lookup", - is_write, - Target::CallContext, - RwValues::new( - call_id.unwrap_or_else(|| self.curr.state.call_id.expr()), - 0.expr(), - field_tag.expr(), - Word::zero(), - Word::from_lo_unchecked(value), - Word::zero(), - 0.expr(), - 0.expr(), - ), - ); - } - pub(crate) fn call_context_lookup_read( &mut self, call_id: Option>, @@ -1397,13 +1157,12 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { Word::zero(), value, Word::zero(), - 0.expr(), - 0.expr(), + Word::zero(), ), ); } - pub(crate) fn call_context_lookup_write_unchecked( + pub(crate) fn call_context_lookup_write( &mut self, call_id: Option>, field_tag: CallContextFieldTag, @@ -1420,8 +1179,7 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { Word::zero(), value, Word::zero(), - 0.expr(), - 0.expr(), + Word::zero(), ), ); } @@ -1438,10 +1196,9 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { .map(|field_tag| { let cell = self.query_cell(); if is_write { - self.call_context_lookup_write_unchecked( + self.call_context_lookup_write( call_id.clone(), field_tag, - // TODO assure range check since write=true also possible Word::from_lo_unchecked(cell.expr()), ); } else { @@ -1473,7 +1230,7 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { self.reversion_info(call_id, false) } - pub(crate) fn reversion_info_write( + pub(crate) fn reversion_info_write_unchecked( &mut self, call_id: Option>, ) -> ReversionInfo { @@ -1481,21 +1238,6 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { } // Stack - - #[deprecated(note = "stack_pop_word is favored")] - pub(crate) fn stack_pop(&mut self, value: Expression) { - // This is definitely incorrct. The intention is to convert expression to word to fix build. - let value = Word::from_lo_unchecked(value); - self.stack_pop_word(value) - } - - #[deprecated(note = "stack_push_word is favored")] - pub(crate) fn stack_push(&mut self, value: Expression) { - // This is definitely incorrct. The intention is to convert expression to word to fix build. - let value = Word::from_lo_unchecked(value); - self.stack_push_word(value) - } - pub(crate) fn stack_pop_word(&mut self, value: Word>) { self.stack_lookup_word(false.expr(), self.stack_pointer_offset.clone(), value); self.stack_pointer_offset = self.stack_pointer_offset.clone() + self.condition_expr(); @@ -1505,19 +1247,6 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { self.stack_pointer_offset = self.stack_pointer_offset.clone() - self.condition_expr(); self.stack_lookup_word(true.expr(), self.stack_pointer_offset.expr(), value); } - #[deprecated(note = "stack_lookup_word is favored")] - pub(crate) fn stack_lookup( - &mut self, - is_write: Expression, - stack_pointer_offset: Expression, - value: Expression, - ) { - self.stack_lookup_word( - is_write, - stack_pointer_offset, - Word::from_lo_unchecked(value), - ) - } pub(crate) fn stack_lookup_word( &mut self, @@ -1536,8 +1265,7 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { Word::zero(), value, Word::zero(), - 0.expr(), - 0.expr(), + Word::zero(), ), ); } @@ -1563,19 +1291,18 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { // TODO assure range check since write=true also possible Word::from_lo_unchecked(byte), Word::zero(), - 0.expr(), - 0.expr(), + Word::zero(), ), ); } - pub(crate) fn tx_log_lookup( + pub(crate) fn tx_log_lookup_word( &mut self, tx_id: Expression, log_id: Expression, field_tag: TxLogFieldTag, index: Expression, - value: Expression, + value: Word>, ) { self.rw_lookup( "log data lookup", @@ -1586,17 +1313,14 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { build_tx_log_expression(index, field_tag.expr(), log_id), 0.expr(), Word::zero(), - // TODO assure range check since here is write - Word::from_lo_unchecked(value), + value, + Word::zero(), Word::zero(), - 0.expr(), - 0.expr(), ), ); } // Tx Receipt - pub(crate) fn tx_receipt_lookup( &mut self, is_write: Expression, @@ -1616,8 +1340,7 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { // TODO assure range check since write=true also possible Word::from_lo_unchecked(value), Word::zero(), - 0.expr(), - 0.expr(), + Word::zero(), ), ); } @@ -1637,8 +1360,7 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { storage_key: Word::zero(), value: Word::zero(), value_prev: Word::zero(), - aux1: 0.expr(), - aux2: 0.expr(), + init_val: Word::zero(), }, ); } @@ -1648,9 +1370,9 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { #[allow(clippy::too_many_arguments)] pub(crate) fn copy_table_lookup( &mut self, - src_id: Expression, + src_id: Word>, src_tag: Expression, - dst_id: Expression, + dst_id: Word>, dst_tag: Expression, src_addr: Expression, src_addr_end: Expression, @@ -1703,17 +1425,6 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { } // Keccak Table - - #[deprecated(note = "keccak_table_lookup_word is fav")] - pub(crate) fn keccak_table_lookup( - &mut self, - input_rlc: Expression, - input_len: Expression, - output: Expression, - ) { - self.keccak_table_lookup_word(input_rlc, input_len, Word::from_lo_unchecked(output)) - } - pub(crate) fn keccak_table_lookup_word( &mut self, input_rlc: Expression, diff --git a/zkevm-circuits/src/evm_circuit/util/math_gadget.rs b/zkevm-circuits/src/evm_circuit/util/math_gadget.rs index 225c28951a..17ec3799d3 100644 --- a/zkevm-circuits/src/evm_circuit/util/math_gadget.rs +++ b/zkevm-circuits/src/evm_circuit/util/math_gadget.rs @@ -39,7 +39,7 @@ pub(crate) use is_equal_word::IsEqualWordGadget; pub(crate) use is_zero::IsZeroGadget; pub(crate) use is_zero_word::IsZeroWordGadget; pub(crate) use lt::LtGadget; -pub(crate) use lt_word::{LtWordGadget as LtWordGadgetNew, LtWordGadgetLegacy as LtWordGadget}; +pub(crate) use lt_word::LtWordGadget; pub(crate) use min_max::MinMaxGadget; pub(crate) use modulo::ModGadget; pub(crate) use mul_add_words::MulAddWordsGadget; 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 3aea958a90..8bc22cc43f 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 @@ -1,9 +1,11 @@ use crate::{ - evm_circuit::util::{ - self, - constraint_builder::{ConstrainBuilderCommon, EVMConstraintBuilder}, - math_gadget::*, - CachedRegion, + evm_circuit::{ + param::N_BYTES_WORD, + util::{ + constraint_builder::{ConstrainBuilderCommon, EVMConstraintBuilder}, + math_gadget::*, + CachedRegion, + }, }, util::{ word::{Word32Cell, WordExpr}, @@ -49,10 +51,10 @@ impl AbsWordGadget { // When `is_neg`, constrain `sum == 0` and `carry == 1`. Since the final // result is `1 << 256`. - let add_words = AddWordsGadget::construct_new(cb, [x.clone(), x_abs.clone()], sum.clone()); + let add_words = AddWordsGadget::construct(cb, [x.clone(), x_abs.clone()], sum.clone()); cb.add_constraint( "sum == 0 when x < 0", - is_neg.expr() * sum::expr(add_words.sum().word_expr().limbs), + is_neg.expr() * sum::expr(add_words.sum().to_word_n::().limbs), ); cb.add_constraint( "carry_hi == 1 when x < 0", @@ -75,9 +77,8 @@ impl AbsWordGadget { x: Word, x_abs: Word, ) -> Result<(), Error> { - self.x.assign(region, offset, Some(x.to_le_bytes()))?; - self.x_abs - .assign(region, offset, Some(x_abs.to_le_bytes()))?; + self.x.assign_u256(region, offset, x)?; + self.x_abs.assign_u256(region, offset, x_abs)?; self.is_neg.assign( region, offset, @@ -85,19 +86,10 @@ impl AbsWordGadget { u64::from(x.to_le_bytes()[31]).into(), )?; let sum = x.overflowing_add(x_abs).0; - self.sum.assign(region, offset, Some(sum.to_le_bytes()))?; + self.sum.assign_u256(region, offset, sum)?; self.add_words.assign(region, offset, [x, x_abs], sum) } - #[deprecated(note = "in fav of x_word")] - pub(crate) fn x(&self) -> &util::Word { - todo!() - } - #[deprecated(note = "in fav of x_abs_word")] - pub(crate) fn x_abs(&self) -> &util::Word { - todo!() - } - pub(crate) fn is_neg(&self) -> &LtGadget { &self.is_neg } 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 63ac208b5f..ee947a7d86 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 @@ -5,11 +5,11 @@ use crate::{ pow_of_two_expr, split_u256, sum, CachedRegion, Cell, }, util::{ - word::{Word32Cell, WordExpr, WordLegacy}, + word::{Word32Cell, WordExpr}, Expr, }, }; -use eth_types::{Field, ToLittleEndian, ToScalar, Word}; +use eth_types::{Field, ToScalar, Word}; use halo2_proofs::{circuit::Value, plonk::Error}; /// Construction of 2 256-bit words addition and result, which is useful for @@ -26,13 +26,6 @@ impl AddWordsGadget { pub(crate) fn construct( - _cb: &mut EVMConstraintBuilder, - _addends: [WordLegacy; N_ADDENDS], - _sum: WordLegacy, - ) -> Self { - todo!() - } - pub(crate) fn construct_new( cb: &mut EVMConstraintBuilder, addends: [Word32Cell; N_ADDENDS], sum: Word32Cell, @@ -52,8 +45,7 @@ impl .iter() .map(|addend| addend.to_word().hi()) .collect::>(); - let sum_lo = sum.to_word().lo(); - let sum_hi = sum.to_word().hi(); + let (sum_lo, sum_hi) = sum.to_word().to_lo_hi(); cb.require_equal( "sum(addends_lo) == sum_lo + carry_lo ⋅ 2^128", @@ -102,9 +94,9 @@ impl sum: Word, ) -> Result<(), Error> { for (word, value) in self.addends.iter().zip(addends.iter()) { - word.assign(region, offset, Some(value.to_le_bytes()))?; + word.assign_u256(region, offset, *value)?; } - self.sum.assign(region, offset, Some(sum.to_le_bytes()))?; + self.sum.assign_u256(region, offset, sum)?; let (addends_lo, addends_hi): (Vec<_>, Vec<_>) = addends.iter().map(split_u256).unzip(); let (sum_lo, sum_hi) = split_u256(&sum); @@ -181,7 +173,7 @@ mod tests { fn configure_gadget_container(cb: &mut EVMConstraintBuilder) -> Self { let addends = [(); N_ADDENDS].map(|_| cb.query_word32()); let sum = cb.query_word32(); - let addwords_gadget = AddWordsGadget::::construct_new( + let addwords_gadget = AddWordsGadget::::construct( cb, addends.clone(), sum.clone(), @@ -211,10 +203,10 @@ mod tests { let offset = 0; for (i, addend) in self.addends.iter().enumerate() { let a = witnesses[i]; - addend.assign(region, offset, Some(a.to_le_bytes()))?; + addend.assign_u256(region, offset, a)?; } let sum = witnesses[N_ADDENDS]; - self.sum.assign(region, offset, Some(sum.to_le_bytes()))?; + self.sum.assign_u256(region, offset, sum)?; let addends = witnesses[0..N_ADDENDS].try_into().unwrap(); self.addwords_gadget.assign(region, 0, addends, sum)?; 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 c41ae7819b..1d82f26f0d 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 @@ -129,7 +129,7 @@ mod tests { fn configure_gadget_container(cb: &mut EVMConstraintBuilder) -> Self { let value_word32 = cb.query_word32(); let bytesize_gadget = - ByteSizeGadget::::construct(cb, value_word32.word_expr().limbs); + ByteSizeGadget::::construct(cb, value_word32.to_word_n().limbs); cb.require_equal( "byte size gadget must equal N", bytesize_gadget.byte_size(), @@ -148,7 +148,7 @@ mod tests { ) -> Result<(), Error> { let offset = 0; let x = witnesses[0]; - self.a.assign(region, offset, Some(x.to_le_bytes()))?; + self.a.assign_u256(region, offset, x)?; self.bytesize_gadget.assign(region, offset, x)?; Ok(()) 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 6c73ad4ca9..ed170d9c64 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 @@ -129,8 +129,8 @@ mod tests { let b = witnesses[1]; let offset = 0; - self.a_word.assign(region, offset, Some(a.to_le_bytes()))?; - self.b_word.assign(region, offset, Some(b.to_le_bytes()))?; + self.a_word.assign_u256(region, offset, a)?; + self.b_word.assign_u256(region, offset, b)?; self.cmp_gadget.assign(region, offset, a, b)?; Ok(()) } diff --git a/zkevm-circuits/src/evm_circuit/util/math_gadget/is_equal_word.rs b/zkevm-circuits/src/evm_circuit/util/math_gadget/is_equal_word.rs index 43ba8fb8be..5109d47061 100644 --- a/zkevm-circuits/src/evm_circuit/util/math_gadget/is_equal_word.rs +++ b/zkevm-circuits/src/evm_circuit/util/math_gadget/is_equal_word.rs @@ -25,7 +25,7 @@ pub struct IsEqualWordGadget { } impl, T2: WordExpr> IsEqualWordGadget { - pub(crate) fn construct(cb: &mut EVMConstraintBuilder, lhs: T1, rhs: T2) -> Self { + pub(crate) fn construct(cb: &mut EVMConstraintBuilder, lhs: &T1, rhs: &T2) -> Self { let (lhs_lo, lhs_hi) = lhs.to_word().to_lo_hi(); let (rhs_lo, rhs_hi) = rhs.to_word().to_lo_hi(); let is_zero_lo = IsZeroGadget::construct(cb, lhs_lo - rhs_lo); @@ -51,8 +51,8 @@ impl, T2: WordExpr> IsEqualWordGadget { ) -> Result { let (lhs_lo, lhs_hi) = lhs.to_lo_hi(); let (rhs_lo, rhs_hi) = rhs.to_lo_hi(); - self.is_zero_lo.assign(region, offset, rhs_lo - lhs_lo)?; - self.is_zero_hi.assign(region, offset, rhs_hi - lhs_hi)?; + self.is_zero_lo.assign(region, offset, lhs_lo - rhs_lo)?; + self.is_zero_hi.assign(region, offset, lhs_hi - rhs_hi)?; Ok(F::from(2)) } @@ -68,6 +68,16 @@ impl, T2: WordExpr> IsEqualWordGadget { .map(|(lhs, rhs)| self.assign(region, offset, lhs, rhs)), ) } + + pub(crate) fn assign_u256( + &self, + region: &mut CachedRegion<'_, '_, F>, + offset: usize, + lhs: eth_types::Word, + rhs: eth_types::Word, + ) -> Result { + self.assign(region, offset, Word::from(lhs), Word::from(rhs)) + } } // TODO add unittest diff --git a/zkevm-circuits/src/evm_circuit/util/math_gadget/is_zero_word.rs b/zkevm-circuits/src/evm_circuit/util/math_gadget/is_zero_word.rs index 8b0297d3da..f74ccf6a96 100644 --- a/zkevm-circuits/src/evm_circuit/util/math_gadget/is_zero_word.rs +++ b/zkevm-circuits/src/evm_circuit/util/math_gadget/is_zero_word.rs @@ -1,7 +1,7 @@ use std::marker::PhantomData; use eth_types::Field; -use gadgets::util::{or, Expr}; +use gadgets::util::{and, Expr}; use halo2_proofs::{ circuit::Value, plonk::{Error, Expression}, @@ -25,7 +25,7 @@ pub struct IsZeroWordGadget { } impl> IsZeroWordGadget { - pub(crate) fn construct(cb: &mut EVMConstraintBuilder, word: T) -> Self { + pub(crate) fn construct(cb: &mut EVMConstraintBuilder, word: &T) -> Self { let (word_lo, word_hi) = word.to_word().to_lo_hi(); let inverse_lo = cb.query_cell_with_type(CellType::storage_for_expr(&word_lo)); let inverse_hi = cb.query_cell_with_type(CellType::storage_for_expr(&word_hi)); @@ -56,7 +56,7 @@ impl> IsZeroWordGadget { Self { inverse_lo, inverse_hi, - is_zero: or::expr([is_zero_lo, is_zero_hi]), + is_zero: and::expr([is_zero_lo, is_zero_hi]), _marker: Default::default(), } } @@ -85,6 +85,15 @@ impl> IsZeroWordGadget { }) } + pub(crate) fn assign_u256( + &self, + region: &mut CachedRegion<'_, '_, F>, + offset: usize, + value: eth_types::Word, + ) -> Result { + self.assign(region, offset, Word::from(value)) + } + pub(crate) fn assign_value( &self, region: &mut CachedRegion<'_, '_, F>, 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 619348470b..95c4010353 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 @@ -1,11 +1,8 @@ -use std::marker::PhantomData; - use crate::{ evm_circuit::util::{ - self, constraint_builder::EVMConstraintBuilder, from_bytes, math_gadget::*, split_u256, - CachedRegion, + constraint_builder::EVMConstraintBuilder, math_gadget::*, split_u256, CachedRegion, }, - util::word::WordExpr, + util::word::{self}, }; use eth_types::{Field, Word}; use halo2_proofs::plonk::{Error, Expression}; @@ -13,83 +10,24 @@ use halo2_proofs::plonk::{Error, Expression}; /// Returns `1` when `lhs < rhs`, and returns `0` otherwise. /// lhs and rhs are both 256-bit word. #[derive(Clone, Debug)] -#[deprecated(note = "LtWordGadget is favored")] -pub struct LtWordGadgetLegacy { +pub struct LtWordGadget { comparison_hi: ComparisonGadget, lt_lo: LtGadget, } -impl LtWordGadgetLegacy { - pub(crate) fn construct( +impl LtWordGadget { + pub(crate) fn construct + Clone>( cb: &mut EVMConstraintBuilder, - lhs: &util::Word, - rhs: &util::Word, + lhs: &word::Word, + rhs: &word::Word, ) -> Self { - let comparison_hi = ComparisonGadget::construct( - cb, - from_bytes::expr(&lhs.cells[16..]), - from_bytes::expr(&rhs.cells[16..]), - ); - let lt_lo = LtGadget::construct( - cb, - from_bytes::expr(&lhs.cells[..16]), - from_bytes::expr(&rhs.cells[..16]), - ); - Self { - comparison_hi, - lt_lo, - } - } - - pub(crate) fn expr(&self) -> Expression { - let (hi_lt, hi_eq) = self.comparison_hi.expr(); - hi_lt + hi_eq * self.lt_lo.expr() - } - - pub(crate) fn assign( - &self, - region: &mut CachedRegion<'_, '_, F>, - offset: usize, - lhs: Word, - rhs: Word, - ) -> Result<(), Error> { - let (lhs_lo, lhs_hi) = split_u256(&lhs); - let (rhs_lo, rhs_hi) = split_u256(&rhs); - self.comparison_hi.assign( - region, - offset, - F::from_u128(lhs_hi.as_u128()), - F::from_u128(rhs_hi.as_u128()), - )?; - self.lt_lo.assign( - region, - offset, - F::from_u128(lhs_lo.as_u128()), - F::from_u128(rhs_lo.as_u128()), - )?; - Ok(()) - } -} - -/// Returns `1` when `lhs < rhs`, and returns `0` otherwise. -/// lhs and rhs are both 256-bit word. -#[derive(Clone, Debug)] -pub struct LtWordGadget { - comparison_hi: ComparisonGadget, - lt_lo: LtGadget, - _marker: PhantomData<(T1, T2)>, -} - -impl, T2: WordExpr> LtWordGadget { - pub(crate) fn construct(cb: &mut EVMConstraintBuilder, lhs: T1, rhs: T2) -> Self { - let lhs_expr = lhs.to_word(); - let rhs_expr = rhs.to_word(); - let comparison_hi = ComparisonGadget::construct(cb, lhs_expr.hi(), rhs_expr.hi()); - let lt_lo = LtGadget::construct(cb, lhs_expr.lo(), rhs_expr.lo()); + let (lhs_lo, lhs_hi) = lhs.to_lo_hi(); + let (rhs_lo, rhs_hi) = rhs.to_lo_hi(); + let comparison_hi = ComparisonGadget::construct(cb, lhs_hi.expr(), rhs_hi.expr()); + let lt_lo = LtGadget::construct(cb, lhs_lo.expr(), rhs_lo.expr()); Self { comparison_hi, lt_lo, - _marker: Default::default(), } } @@ -126,17 +64,17 @@ impl, T2: WordExpr> LtWordGadget { #[cfg(test)] mod tests { use crate::{ - evm_circuit::util::constraint_builder::ConstrainBuilderCommon, util::word::Word32Cell, + evm_circuit::util::constraint_builder::ConstrainBuilderCommon, + util::word::{Word32Cell, WordExpr}, }; use super::{test_util::*, *}; - use eth_types::*; use halo2_proofs::{halo2curves::bn256::Fr, plonk::Error}; #[derive(Clone)] /// LtWordTestContainer: require(a < b) struct LtWordTestContainer { - ltword_gadget: LtWordGadget, Word32Cell>, + ltword_gadget: LtWordGadget, a: Word32Cell, b: Word32Cell, } @@ -145,7 +83,7 @@ mod tests { fn configure_gadget_container(cb: &mut EVMConstraintBuilder) -> Self { let a = cb.query_word32(); let b = cb.query_word32(); - let ltword_gadget = LtWordGadget::::construct(cb, a.clone(), b.clone()); + let ltword_gadget = LtWordGadget::::construct(cb, &a.to_word(), &b.to_word()); cb.require_equal("a < b", ltword_gadget.expr(), 1.expr()); LtWordTestContainer { ltword_gadget, @@ -163,8 +101,8 @@ mod tests { let b = witnesses[1]; let offset = 0; - self.a.assign(region, offset, Some(a.to_le_bytes()))?; - self.b.assign(region, offset, Some(b.to_le_bytes()))?; + self.a.assign_u256(region, offset, a)?; + self.b.assign_u256(region, offset, b)?; self.ltword_gadget.assign(region, 0, a, b)?; Ok(()) diff --git a/zkevm-circuits/src/evm_circuit/util/math_gadget/min_max_word.rs b/zkevm-circuits/src/evm_circuit/util/math_gadget/min_max_word.rs index d76b665f48..00e0fbdd0c 100644 --- a/zkevm-circuits/src/evm_circuit/util/math_gadget/min_max_word.rs +++ b/zkevm-circuits/src/evm_circuit/util/math_gadget/min_max_word.rs @@ -1,40 +1,32 @@ -use std::marker::PhantomData; - use crate::{ - evm_circuit::util::{ - constraint_builder::EVMConstraintBuilder, math_gadget::LtWordGadgetNew as LtWordGadget, - transpose_val_ret, CachedRegion, - }, - util::word::{Word, WordExpr}, + evm_circuit::util::{constraint_builder::EVMConstraintBuilder, CachedRegion}, + util::word::Word, }; use eth_types::{self, Field}; -use halo2_proofs::{ - circuit::Value, - plonk::{Error, Expression}, -}; +use halo2_proofs::plonk::{Error, Expression}; + +use super::LtWordGadget; /// 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`. #[derive(Clone, Debug)] -pub struct MinMaxWordGadget { - lt: LtWordGadget, +pub struct MinMaxWordGadget { + lt: LtWordGadget, min: Word>, max: Word>, - _marker: PhantomData, } -impl + Clone> MinMaxWordGadget { - pub(crate) fn construct(cb: &mut EVMConstraintBuilder, lhs: T, rhs: T) -> Self { - let lt = LtWordGadget::construct(cb, lhs.clone(), rhs.clone()); +impl MinMaxWordGadget { + pub(crate) fn construct( + cb: &mut EVMConstraintBuilder, + lhs: &Word>, + rhs: &Word>, + ) -> Self { + let lt = LtWordGadget::construct(cb, lhs, rhs); let max = Word::select(lt.expr(), rhs.clone(), lhs.clone()); - let min = Word::select(lt.expr(), lhs, rhs); + let min = Word::select(lt.expr(), lhs.clone(), rhs.clone()); - Self { - lt, - min, - max, - _marker: Default::default(), - } + Self { lt, min, max } } pub(crate) fn min(&self) -> Word> { @@ -46,32 +38,14 @@ impl + Clone> MinMaxWordGadget { } fn assign( - &self, - _region: &mut CachedRegion<'_, '_, F>, - _offset: usize, - _lhs: F, - _rhs: F, - ) -> Result<(F, F), Error> { - todo!("lt assign"); - let lt_says_greater = true; - Ok(if lt_says_greater { - (_rhs, _lhs) - } else { - (_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)), - ) + lhs: eth_types::Word, + rhs: eth_types::Word, + ) -> Result<(), Error> { + self.lt.assign(region, offset, lhs, rhs)?; + Ok(()) } } 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 d80ecf02b8..4a8fa8726e 100644 --- a/zkevm-circuits/src/evm_circuit/util/math_gadget/modulo.rs +++ b/zkevm-circuits/src/evm_circuit/util/math_gadget/modulo.rs @@ -1,15 +1,15 @@ use crate::{ evm_circuit::util::{ constraint_builder::{ConstrainBuilderCommon, EVMConstraintBuilder}, - math_gadget::{LtWordGadgetNew as LtWordGadget, *}, - CachedRegion, Word as WordLegacy, + math_gadget::{LtWordGadget, *}, + CachedRegion, }, util::{ - word::{self, Word32Cell}, + word::{self, Word32Cell, WordExpr}, Expr, }, }; -use eth_types::{Field, ToLittleEndian, Word}; +use eth_types::{Field, Word}; use halo2_proofs::{circuit::Value, plonk::Error}; /// Constraints for the words a, n, r: @@ -29,28 +29,18 @@ pub(crate) struct ModGadget { n_is_zero: IsZeroWordGadget>, a_or_is_zero: IsZeroWordGadget>, eq: IsEqualWordGadget, Word32Cell>, - lt: LtWordGadget, Word32Cell>, + lt: LtWordGadget, } impl ModGadget { - pub(crate) fn construct( - _cb: &mut EVMConstraintBuilder, - _words: [&WordLegacy; 3], - ) -> Self { - todo!() - } - - pub(crate) fn construct_new( - cb: &mut EVMConstraintBuilder, - words: [&Word32Cell; 3], - ) -> Self { + pub(crate) fn construct(cb: &mut EVMConstraintBuilder, words: [&Word32Cell; 3]) -> Self { let (a, n, r) = (words[0], words[1], words[2]); let k = cb.query_word32(); let a_or_zero = cb.query_word32(); - let n_is_zero = IsZeroWordGadget::construct(cb, n.clone()); - let a_or_is_zero = IsZeroWordGadget::construct(cb, a_or_zero.clone()); - let mul_add_words = MulAddWordsGadget::construct_new(cb, [&k, n, r, &a_or_zero]); - let eq = IsEqualWordGadget::construct(cb, a.clone(), a_or_zero.clone()); - let lt = LtWordGadget::construct(cb, r.clone(), n.clone()); + let n_is_zero = IsZeroWordGadget::construct(cb, n); + let a_or_is_zero = IsZeroWordGadget::construct(cb, &a_or_zero); + let mul_add_words = MulAddWordsGadget::construct(cb, [&k, n, r, &a_or_zero]); + let eq = IsEqualWordGadget::construct(cb, a, &a_or_zero); + let lt = LtWordGadget::construct(cb, &r.to_word(), &n.to_word()); // Constrain the aux variable a_or_zero to be =a or =0 if n==0: // (a == a_or_zero) ^ (n == 0 & a_or_zero == 0) cb.add_constraint( @@ -90,12 +80,9 @@ impl ModGadget { ) -> Result<(), Error> { let a_or_zero = if n.is_zero() { Word::zero() } else { a }; - self.k.assign(region, offset, Some(k.to_le_bytes()))?; - self.a_or_zero - .assign(region, offset, Some(a_or_zero.to_le_bytes()))?; - let n_sum = (0..32).fold(0, |acc, idx| acc + n.byte(idx) as u64); - self.n_is_zero - .assign(region, offset, word::Word::from(n_sum))?; + self.k.assign_u256(region, offset, k)?; + self.a_or_zero.assign_u256(region, offset, a_or_zero)?; + self.n_is_zero.assign(region, offset, word::Word::from(n))?; self.a_or_is_zero .assign(region, offset, word::Word::from(a_or_zero))?; self.mul_add_words @@ -132,7 +119,7 @@ mod tests { let a = cb.query_word32(); let n = cb.query_word32(); let r = cb.query_word32(); - let mod_gadget = ModGadget::::construct_new(cb, [&a, &n, &r]); + let mod_gadget = ModGadget::::construct(cb, [&a, &n, &r]); ModGadgetTestContainer { mod_gadget, a, @@ -157,9 +144,9 @@ mod tests { let offset = 0; - self.a.assign(region, offset, Some(a.to_le_bytes()))?; - self.n.assign(region, offset, Some(n.to_le_bytes()))?; - self.r.assign(region, offset, Some(r.to_le_bytes()))?; + self.a.assign_u256(region, offset, a)?; + self.n.assign_u256(region, offset, n)?; + self.r.assign_u256(region, offset, r)?; 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 45c0aabf2e..85b9ee0b7c 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 @@ -4,7 +4,7 @@ use crate::{ from_bytes, pow_of_two_expr, split_u256, split_u256_limb64, CachedRegion, Cell, }, util::{ - word::{Word, Word32Cell, Word4, WordExpr, WordLegacy}, + word::{Word, Word32Cell, Word4, WordExpr}, Expr, }, }; @@ -52,17 +52,7 @@ pub(crate) struct MulAddWordsGadget { } impl MulAddWordsGadget { - pub(crate) fn construct( - _cb: &mut EVMConstraintBuilder, - _words: [&WordLegacy; 4], - ) -> Self { - todo!() - } - - pub(crate) fn construct_new( - cb: &mut EVMConstraintBuilder, - words: [&Word32Cell; 4], - ) -> Self { + pub(crate) fn construct(cb: &mut EVMConstraintBuilder, words: [&Word32Cell; 4]) -> Self { let (a, b, c, d) = (words[0], words[1], words[2], words[3]); let carry_lo = cb.query_bytes(); let carry_hi = cb.query_bytes(); @@ -71,8 +61,8 @@ impl MulAddWordsGadget { let mut a_limbs = vec![]; let mut b_limbs = vec![]; - let word4_a: Word4> = a.word_expr().to_word_n(); - let word4_b: Word4> = b.word_expr().to_word_n(); + let word4_a: Word4> = a.to_word_n(); + let word4_b: Word4> = b.to_word_n(); for i in 0..4 { a_limbs.push(word4_a.limbs[i].expr()); b_limbs.push(word4_b.limbs[i].expr()); @@ -184,7 +174,7 @@ mod tests { let c = cb.query_word32(); let d = cb.query_word32(); let carry = cb.query_cell(); - let math_gadget = MulAddWordsGadget::::construct_new(cb, [&a, &b, &c, &d]); + let math_gadget = MulAddWordsGadget::::construct(cb, [&a, &b, &c, &d]); cb.require_equal("carry is correct", math_gadget.overflow(), carry.expr()); MulAddGadgetContainer { muladd_words_gadget: math_gadget, @@ -202,14 +192,10 @@ mod tests { region: &mut CachedRegion<'_, '_, F>, ) -> Result<(), Error> { let offset = 0; - self.a - .assign(region, offset, Some(witnesses[0].to_le_bytes()))?; - self.b - .assign(region, offset, Some(witnesses[1].to_le_bytes()))?; - self.c - .assign(region, offset, Some(witnesses[2].to_le_bytes()))?; - self.d - .assign(region, offset, Some(witnesses[3].to_le_bytes()))?; + self.a.assign_u256(region, offset, witnesses[0])?; + self.b.assign_u256(region, offset, witnesses[1])?; + self.c.assign_u256(region, offset, witnesses[2])?; + self.d.assign_u256(region, offset, witnesses[3])?; self.carry.assign( region, offset, 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 716076cdad..c4becb836e 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 @@ -1,6 +1,5 @@ use crate::{ evm_circuit::util::{ - self, constraint_builder::{ConstrainBuilderCommon, EVMConstraintBuilder}, from_bytes, pow_of_two_expr, split_u256, split_u256_limb64, CachedRegion, Cell, }, @@ -54,15 +53,6 @@ pub(crate) struct MulAddWords512Gadget { } impl MulAddWords512Gadget { - #[deprecated(note = "construct is favored")] - pub(crate) fn legacy_construct( - _cb: &mut EVMConstraintBuilder, - _words: [&util::Word; 4], - _addend: Option<&util::Word>, - ) -> Self { - todo!() - } - /// The words argument is: a, b, d, e /// Addend is the optional c. pub(crate) fn construct( @@ -80,8 +70,8 @@ impl MulAddWords512Gadget { // Split input words in limbs let mut a_limbs = vec![]; let mut b_limbs = vec![]; - let word4_a: Word4> = words[0].word_expr().to_word_n(); - let word4_b: Word4> = words[1].word_expr().to_word_n(); + let word4_a: Word4> = words[0].to_word_n(); + let word4_b: Word4> = words[1].to_word_n(); for i in 0..4 { a_limbs.push(word4_a.limbs[i].expr()); b_limbs.push(word4_b.limbs[i].expr()); @@ -249,16 +239,11 @@ mod tests { region: &mut CachedRegion<'_, '_, F>, ) -> Result<(), Error> { let offset = 0; - self.a - .assign(region, offset, Some(witnesses[0].to_le_bytes()))?; - self.b - .assign(region, offset, Some(witnesses[1].to_le_bytes()))?; - self.d - .assign(region, offset, Some(witnesses[2].to_le_bytes()))?; - self.e - .assign(region, offset, Some(witnesses[3].to_le_bytes()))?; - self.addend - .assign(region, offset, Some(witnesses[4].to_le_bytes()))?; + self.a.assign_u256(region, offset, witnesses[0])?; + self.b.assign_u256(region, offset, witnesses[1])?; + self.d.assign_u256(region, offset, witnesses[2])?; + self.e.assign_u256(region, offset, witnesses[3])?; + self.addend.assign_u256(region, offset, witnesses[4])?; self.math_gadget.assign( region, offset, 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 b44ab22dbb..220235a002 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 @@ -9,7 +9,7 @@ use crate::{ Expr, }, }; -use eth_types::{Field, ToLittleEndian, Word}; +use eth_types::{Field, Word}; use halo2_proofs::{ circuit::Value, plonk::{Error, Expression}, @@ -64,9 +64,8 @@ impl MulWordByU64Gadget { product: Word, ) -> Result<(), Error> { self.multiplicand - .assign(region, offset, Some(multiplicand.to_le_bytes()))?; - self.product - .assign(region, offset, Some(product.to_le_bytes()))?; + .assign_u256(region, offset, multiplicand)?; + self.product.assign_u256(region, offset, product)?; let (multiplicand_lo, _) = split_u256(&multiplicand); let (product_lo, _) = split_u256(&product); @@ -93,7 +92,7 @@ impl MulWordByU64Gadget { mod tests { use super::{super::test_util::*, *}; use crate::evm_circuit::util::Cell; - use eth_types::Word; + use eth_types::{ToLittleEndian, Word}; use halo2_proofs::{halo2curves::bn256::Fr, plonk::Error}; #[derive(Clone)] @@ -129,10 +128,9 @@ mod tests { let product = witnesses[2]; let offset = 0; - self.a.assign(region, offset, Some(a.to_le_bytes()))?; + self.a.assign_u256(region, offset, a)?; self.b.assign(region, offset, Value::known(F::from(b)))?; - self.product - .assign(region, offset, Some(product.to_le_bytes()))?; + self.product.assign_u256(region, offset, product)?; self.mulwords_u64_gadget.assign(region, 0, a, b, product)?; Ok(()) diff --git a/zkevm-circuits/src/evm_circuit/util/math_gadget/rlp.rs b/zkevm-circuits/src/evm_circuit/util/math_gadget/rlp.rs index f8f7f69274..b9efe251ed 100644 --- a/zkevm-circuits/src/evm_circuit/util/math_gadget/rlp.rs +++ b/zkevm-circuits/src/evm_circuit/util/math_gadget/rlp.rs @@ -1,16 +1,23 @@ -use eth_types::{Address, Field, ToLittleEndian, ToScalar, Word}; +use crate::{ + evm_circuit::util::rlc, + util::word::{Word32Cell, WordExpr}, +}; +use eth_types::{Address, Field, ToScalar, Word}; use gadgets::util::{and, expr_from_bytes, not, select, sum, Expr}; use halo2_proofs::{ circuit::Value, plonk::{Error, Expression}, }; -use crate::evm_circuit::{ - param::{N_BYTES_ACCOUNT_ADDRESS, N_BYTES_U64, N_BYTES_WORD}, - util::{ - constraint_builder::{ConstrainBuilderCommon, EVMConstraintBuilder}, - CachedRegion, Cell, RandomLinearCombination, +use crate::{ + evm_circuit::{ + param::{N_BYTES_U64, N_BYTES_WORD}, + util::{ + constraint_builder::{ConstrainBuilderCommon, EVMConstraintBuilder}, + AccountAddress, CachedRegion, Cell, RandomLinearCombination, + }, }, + util::word, }; use super::IsZeroGadget; @@ -197,7 +204,7 @@ impl RlpU64Gadget { #[derive(Clone, Debug)] pub struct ContractCreateGadget { /// Sender address of the contract creation tx. - caller_address: RandomLinearCombination, + caller_address: AccountAddress, /// Sender nonce of the contract creation tx. nonce: RlpU64Gadget, /// Keccak256 hash of init code, used for CREATE2. We don't use a @@ -205,18 +212,18 @@ pub struct ContractCreateGadget { /// RLC in the case of init code hash, for BeginTx and /// CREATE2 respectively. Instead, we store just the bytes and calculate the /// appropriate RLC wherever needed. - code_hash: [Cell; N_BYTES_WORD], + code_hash: Word32Cell, /// Random salt for CREATE2. - salt: [Cell; N_BYTES_WORD], + salt: Word32Cell, } impl ContractCreateGadget { /// Configure and construct the gadget. pub(crate) fn construct(cb: &mut EVMConstraintBuilder) -> Self { - let caller_address = cb.query_keccak_rlc(); + let caller_address = cb.query_account_address(); let nonce = RlpU64Gadget::construct(cb); - let code_hash = array_init::array_init(|_| cb.query_byte()); - let salt = array_init::array_init(|_| cb.query_byte()); + let code_hash = cb.query_word32(); + let salt = cb.query_word32(); Self { caller_address, @@ -243,27 +250,18 @@ impl ContractCreateGadget { self.nonce.assign(region, offset, caller_nonce)?; - for (c, v) in self - .code_hash - .iter() - .zip(code_hash.map(|v| v.to_le_bytes()).unwrap_or_default()) - { - c.assign(region, offset, Value::known(F::from(v as u64)))?; - } - for (c, v) in self - .salt - .iter() - .zip(salt.map(|v| v.to_le_bytes()).unwrap_or_default()) - { - c.assign(region, offset, Value::known(F::from(v as u64)))?; - } + self.code_hash + .assign_u256(region, offset, code_hash.unwrap_or_default())?; + + self.salt + .assign_u256(region, offset, salt.unwrap_or_default())?; Ok(()) } /// Caller address' value. - pub(crate) fn caller_address(&self) -> Expression { - expr_from_bytes(&self.caller_address.cells) + pub(crate) fn caller_address_word(&self) -> word::Word> { + self.caller_address.to_word() } /// Caller nonce's value. @@ -272,21 +270,21 @@ impl ContractCreateGadget { } /// Code hash word RLC. - pub(crate) fn code_hash_word_rlc(&self, cb: &EVMConstraintBuilder) -> Expression { - cb.word_rlc::( - self.code_hash - .iter() - .map(Expr::expr) - .collect::>() - .try_into() - .unwrap(), - ) + #[deprecated(note = "in fav of code_hash_word")] + pub(crate) fn code_hash_word_rlc(&self) -> Expression { + unimplemented!() + } + + /// Code hash word RLC. + pub(crate) fn code_hash_word(&self) -> word::Word> { + self.code_hash.to_word() } /// Code hash keccak RLC. pub(crate) fn code_hash_keccak_rlc(&self, cb: &EVMConstraintBuilder) -> Expression { cb.keccak_rlc::( self.code_hash + .limbs .iter() .map(Expr::expr) .collect::>() @@ -296,9 +294,11 @@ impl ContractCreateGadget { } /// Salt EVM word RLC. + #[deprecated(note = "in fav of salt_word")] pub(crate) fn salt_word_rlc(&self, cb: &EVMConstraintBuilder) -> Expression { cb.word_rlc::( self.salt + .limbs .iter() .map(Expr::expr) .collect::>() @@ -307,10 +307,15 @@ impl ContractCreateGadget { ) } + pub(crate) fn salt_word(&self) -> word::Word> { + self.salt.to_word() + } + /// Salt keccak RLC. pub(crate) fn salt_keccak_rlc(&self, cb: &EVMConstraintBuilder) -> Expression { cb.keccak_rlc::( self.salt + .limbs .iter() .map(Expr::expr) .collect::>() @@ -320,8 +325,11 @@ impl ContractCreateGadget { } /// Caller address' RLC value. - pub(crate) fn caller_address_rlc(&self) -> Expression { - self.caller_address.expr() + pub(crate) fn caller_address_rlc(&self, cb: &EVMConstraintBuilder) -> Expression { + rlc::expr( + &self.caller_address.limbs.clone().map(|x| x.expr()), + cb.challenges().keccak_input(), + ) } /// Caller nonce's RLC value. @@ -359,13 +367,13 @@ impl ContractCreateGadget { let challenge_power_64 = challenge_power_32.clone().square(); let challenge_power_84 = challenge_power_64.clone() * challenge_power_20; (0xff.expr() * challenge_power_84) - + (self.caller_address_rlc() * challenge_power_64) + + (self.caller_address_rlc(cb) * challenge_power_64) + (self.salt_keccak_rlc(cb) * challenge_power_32) + self.code_hash_keccak_rlc(cb) } else { // RLC(RLP([caller_address, caller_nonce])) let challenge_power_21 = challenges[20].clone(); - ((self.caller_address_rlc() + ((self.caller_address_rlc(cb) + (148.expr() * challenge_power_20) + ((213.expr() + self.nonce.rlp_length()) * challenge_power_21)) * self.nonce.challenge_power_rlp_length(cb)) diff --git a/zkevm-circuits/src/evm_circuit/util/memory_gadget.rs b/zkevm-circuits/src/evm_circuit/util/memory_gadget.rs index 5499299f6f..85ff035d3d 100644 --- a/zkevm-circuits/src/evm_circuit/util/memory_gadget.rs +++ b/zkevm-circuits/src/evm_circuit/util/memory_gadget.rs @@ -1,19 +1,15 @@ -use super::{constraint_builder::ConstrainBuilderCommon, CachedRegion, MemoryAddress}; +use super::{constraint_builder::ConstrainBuilderCommon, CachedRegion, MemoryAddress, WordExpr}; use crate::{ evm_circuit::{ param::{N_BYTES_GAS, N_BYTES_MEMORY_ADDRESS, N_BYTES_MEMORY_WORD_SIZE}, util::{ constraint_builder::EVMConstraintBuilder, - from_bytes, - math_gadget::{ - ConstantDivisionGadget, IsZeroGadget, IsZeroWordGadget, MinMaxGadget, - RangeCheckGadget, - }, + math_gadget::{ConstantDivisionGadget, IsZeroGadget, MinMaxGadget, RangeCheckGadget}, select, sum, Cell, }, }, util::{ - word::{Word, Word32Cell}, + word::{Word, WordCell}, Expr, }, }; @@ -79,30 +75,33 @@ pub(crate) mod address_high { /// the RLC value for `memory_offset` need not match the bytes. #[derive(Clone, Debug)] pub(crate) struct MemoryAddressGadget { - memory_offset: Word32Cell, - memory_length: Word32Cell, - memory_length_is_zero: IsZeroWordGadget>, + memory_offset_bytes: MemoryAddress, + memory_offset_word: WordCell, + memory_length: MemoryAddress, + memory_length_is_zero: IsZeroGadget, } impl MemoryAddressGadget { - #[deprecated(note = "construct_new is favored")] pub(crate) fn construct( - _cb: &mut EVMConstraintBuilder, - _memory_offset: Cell, - _memory_length: MemoryAddress, - ) -> Self { - todo!() - } - - pub(crate) fn construct_new( cb: &mut EVMConstraintBuilder, - memory_offset: Word32Cell, - memory_length: Word32Cell, + memory_offset_word: WordCell, + memory_length: MemoryAddress, ) -> Self { - let memory_length_is_zero = IsZeroWordGadget::construct(cb, memory_length.clone()); + let memory_length_is_zero = IsZeroGadget::construct(cb, memory_length.sum_expr()); + let memory_offset_bytes = cb.query_memory_address(); + + let has_length = 1.expr() - memory_length_is_zero.expr(); + cb.condition(has_length, |cb| { + cb.require_equal_word( + "Offset decomposition into 5 bytes", + Word::from_lo_unchecked(memory_offset_bytes.expr()), + memory_offset_word.to_word(), + ); + }); Self { - memory_offset, + memory_offset_bytes, + memory_offset_word, memory_length, memory_length_is_zero, } @@ -115,27 +114,30 @@ impl MemoryAddressGadget { memory_offset: U256, memory_length: U256, ) -> Result { + let memory_offset_bytes = memory_offset.to_le_bytes(); + let memory_length_bytes = memory_length.to_le_bytes(); let memory_length_is_zero = memory_length.is_zero(); - self.memory_offset.assign( + self.memory_offset_bytes.assign( region, offset, if memory_length_is_zero { - Some([0u8; 32]) + Some([0; 5]) } else { - Some(memory_offset.to_le_bytes()) + memory_offset_bytes[..N_BYTES_MEMORY_ADDRESS] + .try_into() + .ok() }, )?; - + self.memory_offset_word + .assign_u256(region, offset, memory_offset)?; self.memory_length - .assign(region, offset, Some(memory_length.to_le_bytes()))?; - + .assign_u256(region, offset, memory_length)?; self.memory_length_is_zero - .assign(region, offset, Word::from(memory_length))?; + .assign(region, offset, sum::value(&memory_length_bytes))?; Ok(if memory_length_is_zero { 0 } else { - address_low::value(memory_offset.to_le_bytes()) - + address_low::value(memory_length.to_le_bytes()) + address_low::value(memory_offset_bytes) + address_low::value(memory_length_bytes) }) } @@ -143,19 +145,13 @@ impl MemoryAddressGadget { 1.expr() - self.memory_length_is_zero.expr() } + // offset is the valid offset. It might not equal the offset pop from stack if + // `self.has_length()` is zero pub(crate) fn offset(&self) -> Expression { - self.has_length() * from_bytes::expr(&self.memory_offset.limbs[..N_BYTES_MEMORY_ADDRESS]) - } - - pub(crate) fn offset_rlc(&self) -> Expression { - self.memory_offset.expr() + self.has_length() * self.memory_offset_bytes.expr() } pub(crate) fn length(&self) -> Expression { - from_bytes::expr(&self.memory_length.limbs[..N_BYTES_MEMORY_ADDRESS]) - } - - pub(crate) fn length_rlc(&self) -> Expression { self.memory_length.expr() } diff --git a/zkevm-circuits/src/super_circuit.rs b/zkevm-circuits/src/super_circuit.rs index a7c20c83c1..6db791c217 100644 --- a/zkevm-circuits/src/super_circuit.rs +++ b/zkevm-circuits/src/super_circuit.rs @@ -416,11 +416,7 @@ impl Circuit for SuperCircuit { ); let rws = &self.state_circuit.rows; - config.block_table.load( - &mut layouter, - &block.context, - Value::known(block.randomness), - )?; + config.block_table.load(&mut layouter, &block.context)?; config .mpt_table diff --git a/zkevm-circuits/src/table.rs b/zkevm-circuits/src/table.rs index c42d8c6ed9..fa8f5ab10a 100644 --- a/zkevm-circuits/src/table.rs +++ b/zkevm-circuits/src/table.rs @@ -1,7 +1,7 @@ //! Table definitions used cross-circuits use crate::{ - copy_circuit::util::number_or_hash_to_field, + copy_circuit::util::number_or_hash_to_word, evm_circuit::util::rlc, impl_expr, util::{build_tx_log_address, keccak, word, Challenges}, diff --git a/zkevm-circuits/src/table/block_table.rs b/zkevm-circuits/src/table/block_table.rs index 80e81c4459..47d93dada2 100644 --- a/zkevm-circuits/src/table/block_table.rs +++ b/zkevm-circuits/src/table/block_table.rs @@ -54,7 +54,6 @@ impl BlockTable { &self, layouter: &mut impl Layouter, block: &BlockContext, - randomness: Value, ) -> Result<(), Error> { layouter.assign_region( || "block table", @@ -71,7 +70,7 @@ impl BlockTable { offset += 1; let block_table_columns = >::advice_columns(self); - for row in block.table_assignments(randomness) { + for row in block.table_assignments::() { for (&column, value) in block_table_columns.iter().zip_eq(row) { region.assign_advice( || format!("block table row {}", offset), diff --git a/zkevm-circuits/src/table/bytecode_table.rs b/zkevm-circuits/src/table/bytecode_table.rs index 32ea26a17c..2132106fa8 100644 --- a/zkevm-circuits/src/table/bytecode_table.rs +++ b/zkevm-circuits/src/table/bytecode_table.rs @@ -50,7 +50,6 @@ impl BytecodeTable { &self, layouter: &mut impl Layouter, bytecodes: impl IntoIterator + Clone, - challenges: &Challenges>, ) -> Result<(), Error> { layouter.assign_region( || "bytecode table", @@ -69,7 +68,7 @@ impl BytecodeTable { let bytecode_table_columns = >::advice_columns(self); for bytecode in bytecodes.clone() { - for row in bytecode.table_assignments(challenges) { + for row in bytecode.table_assignments::() { for (&column, value) in bytecode_table_columns.iter().zip_eq(row) { region.assign_advice( || format!("bytecode table row {}", offset), diff --git a/zkevm-circuits/src/table/copy_table.rs b/zkevm-circuits/src/table/copy_table.rs index aebbaf197a..b65d34923a 100644 --- a/zkevm-circuits/src/table/copy_table.rs +++ b/zkevm-circuits/src/table/copy_table.rs @@ -1,7 +1,7 @@ use super::*; -type CopyTableRow = [(Value, &'static str); 8]; -type CopyCircuitRow = [(Value, &'static str); 4]; +type CopyTableRow = [(Value, &'static str); 9]; +type CopyCircuitRow = [(Value, &'static str); 5]; /// Copy Table, used to verify copies of byte chunks between Memory, Bytecode, /// TxLogs and TxCallData. @@ -61,7 +61,7 @@ impl CopyTable { ) -> Vec<(CopyDataType, CopyTableRow, CopyCircuitRow)> { let mut assignments = Vec::new(); // rlc_acc - let rlc_acc = if copy_event.dst_type == CopyDataType::RlcAcc { + let rlc_acc = { let values = copy_event .bytes .iter() @@ -70,8 +70,6 @@ impl CopyTable { challenges .keccak_input() .map(|keccak_input| rlc::value(values.iter().rev(), keccak_input)) - } else { - Value::known(F::ZERO) }; let mut value_acc = Value::known(F::ZERO); for (step_idx, (is_read_step, copy_step)) in copy_event @@ -109,9 +107,9 @@ impl CopyTable { // id let id = if is_read_step { - number_or_hash_to_field(©_event.src_id, challenges.evm_word()) + number_or_hash_to_word(©_event.src_id) } else { - number_or_hash_to_field(©_event.dst_id, challenges.evm_word()) + number_or_hash_to_word(©_event.dst_id) }; // tag binary bumber chip @@ -146,17 +144,11 @@ impl CopyTable { // bytes_left let bytes_left = u64::try_from(copy_event.bytes.len() * 2 - step_idx).unwrap() / 2; // value - let value = if copy_event.dst_type == CopyDataType::RlcAcc { - if is_read_step { - Value::known(F::from(copy_step.value as u64)) - } else { - value_acc = value_acc * challenges.keccak_input() - + Value::known(F::from(copy_step.value as u64)); - value_acc - } - } else { - Value::known(F::from(copy_step.value as u64)) - }; + let value = Value::known(F::from(copy_step.value as u64)); + // value_acc + if is_read_step { + value_acc = value_acc * challenges.keccak_input() + value; + } // is_pad let is_pad = Value::known(F::from( (is_read_step && copy_step_addr >= copy_event.src_addr_end) as u64, @@ -169,14 +161,22 @@ impl CopyTable { tag, [ (is_first, "is_first"), - (id, "id"), + (id.lo(), "id_lo"), + (id.hi(), "id_hi"), (addr, "addr"), ( Value::known(F::from(copy_event.src_addr_end)), "src_addr_end", ), (Value::known(F::from(bytes_left)), "bytes_left"), - (rlc_acc, "rlc_acc"), + ( + match (copy_event.src_type, copy_event.dst_type) { + (CopyDataType::Memory, CopyDataType::Bytecode) => rlc_acc, + (_, CopyDataType::RlcAcc) => rlc_acc, + _ => Value::known(F::ZERO), + }, + "rlc_acc", + ), ( Value::known(F::from(copy_event.rw_counter(step_idx))), "rw_counter", @@ -189,6 +189,7 @@ impl CopyTable { [ (is_last, "is_last"), (value, "value"), + (value_acc, "value_acc"), (is_pad, "is_pad"), (is_code, "is_code"), ], diff --git a/zkevm-circuits/src/table/rw_table.rs b/zkevm-circuits/src/table/rw_table.rs index e8f8ad67e4..6e8ffc4257 100644 --- a/zkevm-circuits/src/table/rw_table.rs +++ b/zkevm-circuits/src/table/rw_table.rs @@ -88,11 +88,11 @@ impl RwTable { row: &RwRow>, ) -> Result<(), Error> { for (column, value) in [ - (self.address, row.address), (self.rw_counter, row.rw_counter), (self.is_write, row.is_write), (self.tag, row.tag), (self.id, row.id), + (self.address, row.address), (self.field_tag, row.field_tag), ] { region.assign_advice(|| "assign rw row on rw table", column, offset, || value)?; diff --git a/zkevm-circuits/src/table/tx_table.rs b/zkevm-circuits/src/table/tx_table.rs index 706aa5983b..d12beafb57 100644 --- a/zkevm-circuits/src/table/tx_table.rs +++ b/zkevm-circuits/src/table/tx_table.rs @@ -95,7 +95,6 @@ impl TxTable { txs: &[Transaction], max_txs: usize, max_calldata: usize, - challenges: &Challenges>, ) -> Result<(), Error> { assert!( txs.len() <= max_txs, @@ -116,7 +115,7 @@ impl TxTable { offset: usize, advice_columns: &[Column], tag: &Column, - row: &[Value; 4], + row: &[Value; 5], msg: &str, ) -> Result<(), Error> { for (index, column) in advice_columns.iter().enumerate() { @@ -140,14 +139,18 @@ impl TxTable { || "tx table", |mut region| { let mut offset = 0; - let advice_columns = - [vec![self.tx_id, self.index], self.value_word.limbs.to_vec()].concat(); + let advice_columns = [ + self.tx_id, + self.index, + self.value_word.lo(), + self.value_word.hi(), + ]; assign_row( &mut region, offset, &advice_columns, &self.tag, - &[(); 4].map(|_| Value::known(F::ZERO)), + &[(); 5].map(|_| Value::known(F::ZERO)), "all-zero", )?; offset += 1; @@ -157,7 +160,7 @@ impl TxTable { // region that has a size parametrized by max_calldata with all // the tx calldata. This is required to achieve a constant fixed column tag // regardless of the number of input txs or the calldata size of each tx. - let mut calldata_assignments: Vec<[Value; 4]> = Vec::new(); + let mut calldata_assignments: Vec<[Value; 5]> = Vec::new(); // Assign Tx data (all tx fields except for calldata) let padding_txs: Vec<_> = (txs.len()..max_txs) .map(|i| Transaction { @@ -166,7 +169,7 @@ impl TxTable { }) .collect(); for tx in txs.iter().chain(padding_txs.iter()) { - let [tx_data, tx_calldata] = tx.table_assignments(*challenges); + let [tx_data, tx_calldata] = tx.table_assignments(); for row in tx_data { assign_row(&mut region, offset, &advice_columns, &self.tag, &row, "")?; offset += 1; @@ -180,6 +183,7 @@ impl TxTable { Value::known(F::from(TxContextFieldTag::CallData as u64)), Value::known(F::ZERO), Value::known(F::ZERO), + Value::known(F::ZERO), ] }); for row in calldata_assignments.into_iter().chain(padding_calldata) { diff --git a/zkevm-circuits/src/util.rs b/zkevm-circuits/src/util.rs index b669e5e2c8..6eea1764ed 100644 --- a/zkevm-circuits/src/util.rs +++ b/zkevm-circuits/src/util.rs @@ -1,4 +1,5 @@ //! Common utility traits and functions. +pub mod int_decomposition; pub mod word; use bus_mapping::evm::OpcodeId; diff --git a/zkevm-circuits/src/util/int_decomposition.rs b/zkevm-circuits/src/util/int_decomposition.rs new file mode 100644 index 0000000000..51b57d33d9 --- /dev/null +++ b/zkevm-circuits/src/util/int_decomposition.rs @@ -0,0 +1,108 @@ +//! Define IntDecomposition to decompose int into byte limbs +use eth_types::{Field, ToLittleEndian, H160, U256}; +use gadgets::util::{sum, Expr}; +use halo2_proofs::{ + circuit::{AssignedCell, Value}, + plonk::{Error, Expression}, +}; +use itertools::Itertools; + +use crate::evm_circuit::{ + param::{MAX_N_BYTES_INTEGER, N_BYTES_HALF_WORD}, + util::{rlc, CachedRegion, Cell}, +}; + +use super::word::{Word, WordExpr}; + +#[derive(Clone, Debug)] +/// IntDecomposition decompose integer into byte limbs +pub struct IntDecomposition { + /// inner cells in little-endian for synthesis + pub limbs: [Cell; N_LIMBS], +} + +impl IntDecomposition { + /// new by cell limbs + pub fn new(limbs: [Cell; N_LIMBS]) -> Self { + Self { limbs } + } + + /// assign bytes to cells + pub fn assign( + &self, + region: &mut CachedRegion<'_, '_, F>, + offset: usize, + bytes: Option<[u8; N_BYTES]>, + ) -> Result>, Error> { + assert!(N_BYTES >= N_LIMBS); + if let Some(bytes) = bytes { + if N_BYTES > N_LIMBS { + for byte in &bytes[N_BYTES - N_LIMBS..] { + assert_eq!(*byte, 0); + } + } + } + bytes.map_or(Err(Error::Synthesis), |bytes| { + self.limbs + .iter() + .zip(bytes.iter()) + .map(|(cell, byte)| { + cell.assign(region, offset, Value::known(F::from(*byte as u64))) + }) + .collect() + }) + } + + /// assign h160 to cells + pub fn assign_h160( + &self, + region: &mut CachedRegion<'_, '_, F>, + offset: usize, + h160: H160, + ) -> Result>, Error> { + let mut bytes = *h160.as_fixed_bytes(); + bytes.reverse(); + self.assign(region, offset, Some(bytes)) + } + + /// assign u256 to cells + pub fn assign_u256( + &self, + region: &mut CachedRegion<'_, '_, F>, + offset: usize, + u256: U256, + ) -> Result>, Error> { + self.assign(region, offset, Some(u256.to_le_bytes())) + } + + /// assign all limbs into one expression + pub fn sum_expr(&self) -> Expression { + sum::expr(self.limbs.clone()) + } +} + +impl Expr for IntDecomposition { + fn expr(&self) -> Expression { + assert!(N_LIMBS <= MAX_N_BYTES_INTEGER); + rlc::expr(&self.limbs.clone().map(|limb| limb.expr()), 256.expr()) + } +} + +impl WordExpr for IntDecomposition { + fn to_word(&self) -> Word> { + let exprs = self + .limbs + .clone() + .map(|x| x.expr()) + .chunks(N_BYTES_HALF_WORD) + .map(|chunk| rlc::expr(chunk, 256.expr())) + .collect::>>(); + Word::new( + (0..2) + .map(|id| exprs.get(id).unwrap_or(&0.expr()).clone()) + .collect_vec() + .try_into() + .unwrap(), + ) + } +} diff --git a/zkevm-circuits/src/util/word.rs b/zkevm-circuits/src/util/word.rs index ca9bb34a3c..4582640586 100644 --- a/zkevm-circuits/src/util/word.rs +++ b/zkevm-circuits/src/util/word.rs @@ -3,7 +3,7 @@ // - Limbs: An EVN word is 256 bits. Limbs N means split 256 into N limb. For example, N = 4, each // limb is 256/4 = 64 bits -use eth_types::{Field, ToLittleEndian, H160}; +use eth_types::{Field, ToLittleEndian, H160, H256}; use gadgets::util::{not, or, Expr}; use halo2_proofs::{ circuit::{AssignedCell, Region, Value}, @@ -93,7 +93,7 @@ impl WordLimbs, N> { /// e.g. N1 = 4 bytes, [b1, b2, b3, b4], and N = 2 limbs [l1, l2] /// It equivalent `l1.assign(b1.expr() + b2.expr * F(256))`, `l2.assign(b3.expr() + b4.expr * /// F(256))` - pub fn assign( + fn assign( &self, region: &mut CachedRegion<'_, '_, F>, offset: usize, @@ -135,7 +135,7 @@ impl WordLimbs, N> { let bytes_lo_assigned = bytes_lo_le .chunks(N_LO / half_limb_size) // chunk in little endian .map(|chunk| from_bytes::value(chunk)) - .zip(self.limbs[0..half_limb_size].iter()) + .zip_eq(self.limbs[0..half_limb_size].iter()) .map(|(value, cell)| cell.assign(region, offset, Value::known(value))) .collect::>, _>>()?; @@ -144,7 +144,7 @@ impl WordLimbs, N> { bytes .chunks(N_HI / half_limb_size) // chunk in little endian .map(|chunk| from_bytes::value(chunk)) - .zip(self.limbs[half_limb_size..].iter()) + .zip_eq(self.limbs[half_limb_size..].iter()) .map(|(value, cell)| cell.assign(region, offset, Value::known(value))) .collect::>, _>>() }); @@ -201,11 +201,15 @@ impl WordLimbs, N> { self.assign_lo_hi(region, offset, value.to_le_bytes(), Option::<[u8; 0]>::None) } - #[deprecated(note = "in fav of to_word trait. Make this private")] /// word expr - pub fn word_expr(&self) -> WordLimbs, N> { + fn word_expr(&self) -> WordLimbs, N> { WordLimbs::new(self.limbs.clone().map(|cell| cell.expr())) } + + /// convert from N cells to N2 expressions limbs + pub fn to_word_n(&self) -> WordLimbs, N2> { + self.word_expr().to_word_n() + } } impl WordExpr for WordLimbs, N> { @@ -290,6 +294,21 @@ impl From for Word { } } +impl From for Word { + /// Construct the word from u256 + fn from(h: H256) -> Self { + let le_bytes = { + let mut b = h.to_fixed_bytes(); + b.reverse(); + b + }; + Word::new([ + from_bytes::value(&le_bytes[..N_BYTES_HALF_WORD]), + from_bytes::value(&le_bytes[N_BYTES_HALF_WORD..]), + ]) + } +} + impl From for Word { /// Construct the word from u64 fn from(value: u64) -> Self { @@ -323,21 +342,6 @@ impl From for Word { } } -impl Word> { - /// Assign low 128 bits for the word - pub fn assign_lo( - &self, - region: &mut CachedRegion<'_, '_, F>, - offset: usize, - value: Value, - ) -> Result>, Error> { - Ok(vec![ - self.limbs[0].assign(region, offset, value)?, - self.limbs[1].assign(region, offset, Value::known(F::from(0)))?, - ]) - } -} - impl Word> { /// Assign advice pub fn assign_advice( @@ -375,22 +379,24 @@ impl Word> { Self(WordLimbs::, 2>::new([0.expr(), 0.expr()])) } + /// one word + pub fn one() -> Self { + Self(WordLimbs::, 2>::new([1.expr(), 0.expr()])) + } + /// select based on selector. Here assume selector is 1/0 therefore no overflow check - pub fn select>( - selector: Expression, - when_true: T, - when_false: T, + pub fn select + Clone>( + selector: T, + when_true: Word, + when_false: Word, ) -> Word> { - let (true_lo, true_hi) = when_true - .to_word() - .mul_selector(selector.clone()) - .to_lo_hi(); + let (true_lo, true_hi) = when_true.to_lo_hi(); - let (false_lo, false_hi) = when_false - .to_word() - .mul_selector(1.expr() - selector) - .to_lo_hi(); - Word::new([true_lo + false_lo, true_hi + false_hi]) + let (false_lo, false_hi) = when_false.to_lo_hi(); + Word::new([ + selector.expr() * true_lo.expr() + (1.expr() - selector.expr()) * false_lo.expr(), + selector.expr() * true_hi.expr() + (1.expr() - selector.expr()) * false_hi.expr(), + ]) } /// Assume selector is 1/0 therefore no overflow check @@ -408,12 +414,9 @@ impl Word> { Word::new([self.lo() - rhs.lo(), self.hi() - rhs.hi()]) } - /// Compress the lo and hi limbs into an expression without checking the overflow. - /// So far only use it for address. - /// TODO We should remove it before merging to the main branch. - #[deprecated(note = "no overflow check and unsafe. please consider keep word type")] - pub fn expr_unchecked(&self) -> Expression { - self.lo() + self.hi() * (1 << (N_BYTES_HALF_WORD * 8)).expr() + /// No overflow check on lo/hi limbs + pub fn mul_unchecked(self, rhs: Self) -> Self { + Word::new([self.lo() * rhs.lo(), self.hi() * rhs.hi()]) } } diff --git a/zkevm-circuits/src/witness/block.rs b/zkevm-circuits/src/witness/block.rs index e3c4de3764..2f45a75339 100644 --- a/zkevm-circuits/src/witness/block.rs +++ b/zkevm-circuits/src/witness/block.rs @@ -1,16 +1,16 @@ use std::collections::HashMap; use crate::{ - evm_circuit::{detect_fixed_table_tags, util::rlc, EvmCircuit}, + evm_circuit::{detect_fixed_table_tags, EvmCircuit}, exp_circuit::param::OFFSET_INCREMENT, table::BlockContextFieldTag, - util::{log2_ceil, SubCircuit}, + util::{log2_ceil, word, SubCircuit}, }; use bus_mapping::{ circuit_input_builder::{self, CircuitsParams, CopyEvent, ExpEvent}, Error, }; -use eth_types::{Address, Field, ToLittleEndian, ToScalar, Word}; +use eth_types::{Address, Field, ToScalar, Word}; use halo2_proofs::circuit::Value; use super::{tx::tx_convert, Bytecode, ExecStep, Rw, RwMap, Transaction}; @@ -152,46 +152,50 @@ pub struct BlockContext { impl BlockContext { /// Assignments for block table - pub fn table_assignments(&self, randomness: Value) -> Vec<[Value; 3]> { + pub fn table_assignments(&self) -> Vec<[Value; 4]> { [ vec![ [ Value::known(F::from(BlockContextFieldTag::Coinbase as u64)), Value::known(F::ZERO), - Value::known(self.coinbase.to_scalar().unwrap()), + Value::known(word::Word::from(self.coinbase).lo()), + Value::known(word::Word::from(self.coinbase).hi()), ], [ Value::known(F::from(BlockContextFieldTag::Timestamp as u64)), Value::known(F::ZERO), Value::known(self.timestamp.to_scalar().unwrap()), + Value::known(F::ZERO), ], [ Value::known(F::from(BlockContextFieldTag::Number as u64)), Value::known(F::ZERO), Value::known(self.number.to_scalar().unwrap()), + Value::known(F::ZERO), ], [ Value::known(F::from(BlockContextFieldTag::Difficulty as u64)), Value::known(F::ZERO), - randomness - .map(|randomness| rlc::value(&self.difficulty.to_le_bytes(), randomness)), + Value::known(word::Word::from(self.difficulty).lo()), + Value::known(word::Word::from(self.difficulty).hi()), ], [ Value::known(F::from(BlockContextFieldTag::GasLimit as u64)), Value::known(F::ZERO), Value::known(F::from(self.gas_limit)), + Value::known(F::ZERO), ], [ Value::known(F::from(BlockContextFieldTag::BaseFee as u64)), Value::known(F::ZERO), - randomness - .map(|randomness| rlc::value(&self.base_fee.to_le_bytes(), randomness)), + Value::known(word::Word::from(self.base_fee).lo()), + Value::known(word::Word::from(self.base_fee).hi()), ], [ Value::known(F::from(BlockContextFieldTag::ChainId as u64)), Value::known(F::ZERO), - randomness - .map(|randomness| rlc::value(&self.chain_id.to_le_bytes(), randomness)), + Value::known(word::Word::from(self.chain_id).lo()), + Value::known(word::Word::from(self.chain_id).hi()), ], ], { @@ -203,8 +207,8 @@ impl BlockContext { [ Value::known(F::from(BlockContextFieldTag::BlockHash as u64)), Value::known((self.number - len_history + idx).to_scalar().unwrap()), - randomness - .map(|randomness| rlc::value(&hash.to_le_bytes(), randomness)), + Value::known(word::Word::from(*hash).lo()), + Value::known(word::Word::from(*hash).hi()), ] }) .collect() diff --git a/zkevm-circuits/src/witness/bytecode.rs b/zkevm-circuits/src/witness/bytecode.rs index 4e945dc380..c3531629d2 100644 --- a/zkevm-circuits/src/witness/bytecode.rs +++ b/zkevm-circuits/src/witness/bytecode.rs @@ -1,9 +1,9 @@ use bus_mapping::evm::OpcodeId; -use eth_types::{Field, ToLittleEndian, Word}; +use eth_types::{Field, Word}; use halo2_proofs::circuit::Value; use sha3::{Digest, Keccak256}; -use crate::{evm_circuit::util::rlc, table::BytecodeFieldTag, util::Challenges}; +use crate::{table::BytecodeFieldTag, util::word}; /// Bytecode #[derive(Clone, Debug)] @@ -22,18 +22,13 @@ impl Bytecode { } /// Assignments for bytecode table - pub fn table_assignments( - &self, - challenges: &Challenges>, - ) -> Vec<[Value; 5]> { + pub fn table_assignments(&self) -> Vec<[Value; 6]> { let n = 1 + self.bytes.len(); let mut rows = Vec::with_capacity(n); - let hash = challenges - .evm_word() - .map(|challenge| rlc::value(&self.hash.to_le_bytes(), challenge)); rows.push([ - hash, + Value::known(word::Word::from(self.hash).lo()), + Value::known(word::Word::from(self.hash).hi()), Value::known(F::from(BytecodeFieldTag::Header as u64)), Value::known(F::ZERO), Value::known(F::ZERO), @@ -52,7 +47,8 @@ impl Bytecode { }; rows.push([ - hash, + Value::known(word::Word::from(self.hash).lo()), + Value::known(word::Word::from(self.hash).hi()), Value::known(F::from(BytecodeFieldTag::Byte as u64)), Value::known(F::from(idx as u64)), Value::known(F::from(is_code as u64)), diff --git a/zkevm-circuits/src/witness/tx.rs b/zkevm-circuits/src/witness/tx.rs index 38be201d3f..0068e312bf 100644 --- a/zkevm-circuits/src/witness/tx.rs +++ b/zkevm-circuits/src/witness/tx.rs @@ -1,8 +1,9 @@ +use crate::util::word; use bus_mapping::circuit_input_builder; -use eth_types::{Address, Field, ToLittleEndian, ToScalar, Word}; +use eth_types::{Address, Field, Word}; use halo2_proofs::circuit::Value; -use crate::{evm_circuit::util::rlc, table::TxContextFieldTag, util::Challenges}; +use crate::table::TxContextFieldTag; use super::{Call, ExecStep}; @@ -40,68 +41,70 @@ pub struct Transaction { impl Transaction { /// Assignments for tx table, split into tx_data (all fields except /// calldata) and tx_calldata - pub fn table_assignments( - &self, - challenges: Challenges>, - ) -> [Vec<[Value; 4]>; 2] { + pub fn table_assignments(&self) -> [Vec<[Value; 5]>; 2] { let tx_data = vec![ [ Value::known(F::from(self.id as u64)), Value::known(F::from(TxContextFieldTag::Nonce as u64)), Value::known(F::ZERO), Value::known(F::from(self.nonce)), + Value::known(F::ZERO), ], [ Value::known(F::from(self.id as u64)), Value::known(F::from(TxContextFieldTag::Gas as u64)), Value::known(F::ZERO), Value::known(F::from(self.gas)), + Value::known(F::ZERO), ], [ Value::known(F::from(self.id as u64)), Value::known(F::from(TxContextFieldTag::GasPrice as u64)), Value::known(F::ZERO), - challenges - .evm_word() - .map(|challenge| rlc::value(&self.gas_price.to_le_bytes(), challenge)), + Value::known(word::Word::from(self.gas_price).lo()), + Value::known(word::Word::from(self.gas_price).hi()), ], [ Value::known(F::from(self.id as u64)), Value::known(F::from(TxContextFieldTag::CallerAddress as u64)), Value::known(F::ZERO), - Value::known(self.caller_address.to_scalar().unwrap()), + Value::known(word::Word::from(self.caller_address).lo()), + Value::known(word::Word::from(self.caller_address).hi()), ], [ Value::known(F::from(self.id as u64)), Value::known(F::from(TxContextFieldTag::CalleeAddress as u64)), Value::known(F::ZERO), - Value::known(self.callee_address.to_scalar().unwrap()), + Value::known(word::Word::from(self.callee_address).lo()), + Value::known(word::Word::from(self.callee_address).hi()), ], [ Value::known(F::from(self.id as u64)), Value::known(F::from(TxContextFieldTag::IsCreate as u64)), Value::known(F::ZERO), Value::known(F::from(self.is_create as u64)), + Value::known(F::ZERO), ], [ Value::known(F::from(self.id as u64)), Value::known(F::from(TxContextFieldTag::Value as u64)), Value::known(F::ZERO), - challenges - .evm_word() - .map(|challenge| rlc::value(&self.value.to_le_bytes(), challenge)), + Value::known(word::Word::from(self.value).lo()), + Value::known(word::Word::from(self.value).hi()), ], [ Value::known(F::from(self.id as u64)), Value::known(F::from(TxContextFieldTag::CallDataLength as u64)), Value::known(F::ZERO), Value::known(F::from(self.call_data_length as u64)), + Value::known(F::ZERO), ], [ Value::known(F::from(self.id as u64)), Value::known(F::from(TxContextFieldTag::CallDataGasCost as u64)), Value::known(F::ZERO), Value::known(F::from(self.call_data_gas_cost)), + Value::known(F::ZERO), ], ]; let tx_calldata = self @@ -114,6 +117,7 @@ impl Transaction { Value::known(F::from(TxContextFieldTag::CallData as u64)), Value::known(F::from(idx as u64)), Value::known(F::from(*byte as u64)), + Value::known(F::ZERO), ] }) .collect();