diff --git a/eth-types/src/lib.rs b/eth-types/src/lib.rs index 5e1184dbddf..374df74b80e 100644 --- a/eth-types/src/lib.rs +++ b/eth-types/src/lib.rs @@ -24,9 +24,12 @@ pub use keccak::{keccak256, Keccak}; pub use bytecode::Bytecode; pub use error::Error; -use halo2_proofs::halo2curves::{ - bn256::{Fq, Fr}, - ff::{Field as Halo2Field, FromUniformBytes, PrimeField}, +use halo2_proofs::{ + halo2curves::{ + bn256::{Fq, Fr}, + ff::{Field as Halo2Field, FromUniformBytes, PrimeField}, + }, + plonk::Expression, }; use crate::evm_types::{memory::Memory, stack::Stack, storage::Storage, OpcodeId}; @@ -42,9 +45,32 @@ pub use ethers_core::{ use serde::{de, Deserialize, Serialize}; use std::{collections::HashMap, fmt, str::FromStr}; +/// trait to serve +pub trait OpsIdentity { + /// output type + type Output; + /// additive identity + fn zero() -> Self::Output; + /// multiplicative identity + fn one() -> Self::Output; +} + +impl OpsIdentity for Expression { + type Output = Expression; + fn zero() -> Self::Output { + Expression::Constant(F::ZERO) + } + + fn one() -> Self::Output { + Expression::Constant(F::ONE) + } +} + /// Trait used to reduce verbosity with the declaration of the [`PrimeField`] /// trait and its repr. -pub trait Field: Halo2Field + PrimeField + FromUniformBytes<64> + Ord { +pub trait Field: + Halo2Field + PrimeField + FromUniformBytes<64> + Ord + OpsIdentity +{ /// Gets the lower 128 bits of this field element when expressed /// canonically. fn get_lower_128(&self) -> u128 { @@ -65,12 +91,34 @@ pub trait Field: Halo2Field + PrimeField + FromUniformBytes<64> } } +impl OpsIdentity for Fr { + type Output = Fr; + + fn zero() -> Self::Output { + Fr::zero() + } + + fn one() -> Self::Output { + Fr::one() + } +} // Impl custom `Field` trait for BN256 Fr to be used and consistent with the // rest of the workspace. impl Field for Fr {} // Impl custom `Field` trait for BN256 Frq to be used and consistent with the // rest of the workspace. +impl OpsIdentity for Fq { + type Output = Fq; + + fn zero() -> Self::Output { + Fq::zero() + } + + fn one() -> Self::Output { + Fq::one() + } +} impl Field for Fq {} /// Trait used to define types that can be converted to a 256 bit scalar value. diff --git a/gadgets/src/util.rs b/gadgets/src/util.rs index dce54c9c351..c8bc889d63a 100644 --- a/gadgets/src/util.rs +++ b/gadgets/src/util.rs @@ -264,7 +264,6 @@ impl Expr for &Expression { (*self).clone() } } - /// Given a bytes-representation of an expression, it computes and returns the /// single expression. pub fn expr_from_bytes>(bytes: &[E]) -> Expression { diff --git a/light-client-poc/src/circuit/state_update.rs b/light-client-poc/src/circuit/state_update.rs index 15464e311b5..92931d98c73 100644 --- a/light-client-poc/src/circuit/state_update.rs +++ b/light-client-poc/src/circuit/state_update.rs @@ -1,5 +1,5 @@ use super::equal_words::EqualWordsConfig; -use eth_types::Field; +use eth_types::{Field, OpsIdentity}; use eyre::Result; use gadgets::{ is_zero::{IsZeroChip, IsZeroConfig, IsZeroInstruction}, @@ -68,7 +68,10 @@ pub struct StateUpdateCircuitConfig { /// MPT Circuit for proving the storage modification is valid. #[derive(Default)] -pub struct StateUpdateCircuit { +pub struct StateUpdateCircuit> +where + ::Output: Field, +{ pub transforms: Transforms, #[cfg(not(feature = "disable-keccak"))] pub keccak_circuit: KeccakCircuit, @@ -78,7 +81,10 @@ pub struct StateUpdateCircuit { pub max_proof_count: usize, } -impl Circuit for StateUpdateCircuit { +impl> Circuit for StateUpdateCircuit +where + ::Output: Field, +{ type Config = (StateUpdateCircuitConfig, Challenges); type FloorPlanner = SimpleFloorPlanner; type Params = MPTCircuitParams; diff --git a/zkevm-circuits/src/evm_circuit/execution/begin_tx.rs b/zkevm-circuits/src/evm_circuit/execution/begin_tx.rs index 9b3c099570b..d0093308645 100644 --- a/zkevm-circuits/src/evm_circuit/execution/begin_tx.rs +++ b/zkevm-circuits/src/evm_circuit/execution/begin_tx.rs @@ -221,12 +221,12 @@ impl ExecutionGadget for BeginTxGadget { cb.account_write( call_callee_address.to_word(), AccountFieldTag::Nonce, - Word::one(), - Word::zero(), + Word::one::>(), + Word::zero::>(), Some(&mut reversion_info), ); for (field_tag, value) in [ - (CallContextFieldTag::Depth, Word::one()), + (CallContextFieldTag::Depth, Word::one::>()), ( CallContextFieldTag::CallerAddress, tx.caller_address.to_word(), @@ -235,24 +235,30 @@ impl ExecutionGadget for BeginTxGadget { CallContextFieldTag::CalleeAddress, call_callee_address.to_word(), ), - (CallContextFieldTag::CallDataOffset, Word::zero()), + ( + CallContextFieldTag::CallDataOffset, + Word::zero::>(), + ), ( CallContextFieldTag::CallDataLength, Word::from_lo_unchecked(tx.call_data_length.expr()), ), (CallContextFieldTag::Value, tx.value.to_word()), - (CallContextFieldTag::IsStatic, Word::zero()), - (CallContextFieldTag::LastCalleeId, Word::zero()), + (CallContextFieldTag::IsStatic, Word::zero::>()), + ( + CallContextFieldTag::LastCalleeId, + Word::zero::>(), + ), ( CallContextFieldTag::LastCalleeReturnDataOffset, - Word::zero(), + Word::zero::>(), ), ( CallContextFieldTag::LastCalleeReturnDataLength, - Word::zero(), + Word::zero::>(), ), - (CallContextFieldTag::IsRoot, Word::one()), - (CallContextFieldTag::IsCreate, Word::one()), + (CallContextFieldTag::IsRoot, Word::one::>()), + (CallContextFieldTag::IsCreate, Word::one::>()), ( CallContextFieldTag::CodeHash, cb.curr.state.code_hash.to_word(), @@ -349,7 +355,7 @@ impl ExecutionGadget for BeginTxGadget { |cb| { // Setup first call's context. for (field_tag, value) in [ - (CallContextFieldTag::Depth, Word::one()), + (CallContextFieldTag::Depth, Word::one::>()), ( CallContextFieldTag::CallerAddress, tx.caller_address.to_word(), @@ -358,23 +364,29 @@ impl ExecutionGadget for BeginTxGadget { CallContextFieldTag::CalleeAddress, tx.callee_address.to_word(), ), - (CallContextFieldTag::CallDataOffset, Word::zero()), + ( + CallContextFieldTag::CallDataOffset, + Word::zero::>(), + ), ( CallContextFieldTag::CallDataLength, Word::from_lo_unchecked(tx.call_data_length.expr()), ), (CallContextFieldTag::Value, tx.value.to_word()), - (CallContextFieldTag::IsStatic, Word::zero()), - (CallContextFieldTag::LastCalleeId, Word::zero()), + (CallContextFieldTag::IsStatic, Word::zero::>()), + ( + CallContextFieldTag::LastCalleeId, + Word::zero::>(), + ), ( CallContextFieldTag::LastCalleeReturnDataOffset, - Word::zero(), + Word::zero::>(), ), ( CallContextFieldTag::LastCalleeReturnDataLength, - Word::zero(), + Word::zero::>(), ), - (CallContextFieldTag::IsRoot, Word::one()), + (CallContextFieldTag::IsRoot, Word::one::>()), ( CallContextFieldTag::IsCreate, Word::from_lo_unchecked(tx.is_create.expr()), diff --git a/zkevm-circuits/src/evm_circuit/execution/callop.rs b/zkevm-circuits/src/evm_circuit/execution/callop.rs index 0c0e6ae6668..f1dbefc40ef 100644 --- a/zkevm-circuits/src/evm_circuit/execution/callop.rs +++ b/zkevm-circuits/src/evm_circuit/execution/callop.rs @@ -32,7 +32,10 @@ use bus_mapping::{ precompile::{is_precompiled, PrecompileCalls}, }; use eth_types::{evm_types::GAS_STIPEND_CALL_WITH_VALUE, Field, ToAddress, ToScalar, U256}; -use halo2_proofs::{circuit::Value, plonk::Error}; +use halo2_proofs::{ + circuit::Value, + plonk::{Error, Expression}, +}; use std::cmp::min; /// Gadget for call related opcodes. It supports `OpcodeId::CALL`, @@ -540,7 +543,7 @@ impl ExecutionGadget for CallOpGadget { CallContextFieldTag::LastCalleeReturnDataOffset, CallContextFieldTag::LastCalleeReturnDataLength, ] { - cb.call_context_lookup_write(None, field_tag, Word::zero()); + 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 @@ -588,7 +591,7 @@ impl ExecutionGadget for CallOpGadget { CallContextFieldTag::LastCalleeReturnDataOffset, CallContextFieldTag::LastCalleeReturnDataLength, ] { - cb.call_context_lookup_write(None, field_tag, Word::zero()); + cb.call_context_lookup_write(None, field_tag, Word::zero::>()); } cb.require_step_state_transition(StepStateTransition { @@ -689,17 +692,20 @@ impl ExecutionGadget for CallOpGadget { CallContextFieldTag::IsStatic, Word::from_lo_unchecked(or::expr([is_static.expr(), is_staticcall.expr()])), ), - (CallContextFieldTag::LastCalleeId, Word::zero()), + ( + CallContextFieldTag::LastCalleeId, + Word::zero::>(), + ), ( CallContextFieldTag::LastCalleeReturnDataOffset, - Word::zero(), + Word::zero::>(), ), ( CallContextFieldTag::LastCalleeReturnDataLength, - Word::zero(), + Word::zero::>(), ), - (CallContextFieldTag::IsRoot, Word::zero()), - (CallContextFieldTag::IsCreate, Word::zero()), + (CallContextFieldTag::IsRoot, Word::zero::>()), + (CallContextFieldTag::IsCreate, Word::zero::>()), ( CallContextFieldTag::CodeHash, call_gadget.callee_code_hash.to_word(), diff --git a/zkevm-circuits/src/evm_circuit/execution/create.rs b/zkevm-circuits/src/evm_circuit/execution/create.rs index 293f18f7c31..a33da085f26 100644 --- a/zkevm-circuits/src/evm_circuit/execution/create.rs +++ b/zkevm-circuits/src/evm_circuit/execution/create.rs @@ -296,7 +296,7 @@ impl ExecutionGadget< CallContextFieldTag::LastCalleeReturnDataOffset, CallContextFieldTag::LastCalleeReturnDataLength, ] { - cb.call_context_lookup_write(None, field_tag, Word::zero()); + cb.call_context_lookup_write(None, field_tag, Word::zero::>()); } cb.require_step_state_transition(StepStateTransition { @@ -342,8 +342,8 @@ impl ExecutionGadget< cb.account_write( contract_addr.to_word(), AccountFieldTag::Nonce, - Word::one(), - Word::zero(), + Word::one::>(), + Word::zero::>(), Some(&mut callee_reversion_info), ); @@ -420,7 +420,11 @@ impl ExecutionGadget< CallContextFieldTag::LastCalleeReturnDataOffset, CallContextFieldTag::LastCalleeReturnDataLength, ] { - cb.call_context_lookup_write(None, field_tag, Word::zero()); + cb.call_context_lookup_write( + None, + field_tag, + Word::zero::>(), + ); } cb.require_step_state_transition(StepStateTransition { rw_counter: Delta(cb.rw_counter_offset()), @@ -463,7 +467,7 @@ impl ExecutionGadget< CallContextFieldTag::LastCalleeReturnDataOffset, CallContextFieldTag::LastCalleeReturnDataLength, ] { - cb.call_context_lookup_write(None, field_tag, Word::zero()); + cb.call_context_lookup_write(None, field_tag, Word::zero::>()); } cb.require_step_state_transition(StepStateTransition { diff --git a/zkevm-circuits/src/evm_circuit/execution/end_block.rs b/zkevm-circuits/src/evm_circuit/execution/end_block.rs index 48e083602b4..512696fbb65 100644 --- a/zkevm-circuits/src/evm_circuit/execution/end_block.rs +++ b/zkevm-circuits/src/evm_circuit/execution/end_block.rs @@ -16,7 +16,10 @@ use crate::{ }; use eth_types::Field; use gadgets::util::select; -use halo2_proofs::{circuit::Value, plonk::Error}; +use halo2_proofs::{ + circuit::Value, + plonk::{Error, Expression}, +}; #[derive(Clone, Debug)] pub(crate) struct EndBlockGadget { @@ -74,7 +77,7 @@ impl ExecutionGadget for EndBlockGadget { total_txs.expr() + 1.expr(), TxContextFieldTag::CallerAddress, None, - Word::zero(), + Word::zero::>(), ); // Since every tx lookup done in the EVM circuit must succeed // and uses a unique tx_id, we know that at diff --git a/zkevm-circuits/src/evm_circuit/execution/error_precompile_failed.rs b/zkevm-circuits/src/evm_circuit/execution/error_precompile_failed.rs index 4945564fb1b..41aa97d9e2f 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_precompile_failed.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_precompile_failed.rs @@ -18,7 +18,10 @@ use crate::{ }; use bus_mapping::evm::OpcodeId; use eth_types::{Field, U256}; -use halo2_proofs::{circuit::Value, plonk::Error}; +use halo2_proofs::{ + circuit::Value, + plonk::{Error, Expression}, +}; #[derive(Clone, Debug)] pub(crate) struct ErrorPrecompileFailedGadget { @@ -87,7 +90,7 @@ impl ExecutionGadget for ErrorPrecompileFailedGadget { cb.stack_pop(cd_length.to_word()); cb.stack_pop(rd_offset.to_word()); cb.stack_pop(rd_length.to_word()); - cb.stack_push(Word::zero()); + cb.stack_push(Word::zero::>()); for (field_tag, value) in [ (CallContextFieldTag::LastCalleeId, callee_call_id.expr()), 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 6182e413d5c..f77011b6750 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_write_protection.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_write_protection.rs @@ -17,7 +17,10 @@ use crate::{ }, }; use eth_types::{evm_types::OpcodeId, Field, ToAddress, U256}; -use halo2_proofs::{circuit::Value, plonk::Error}; +use halo2_proofs::{ + circuit::Value, + plonk::{Error, Expression}, +}; #[derive(Clone, Debug)] pub(crate) struct ErrorWriteProtectionGadget { @@ -73,7 +76,11 @@ impl ExecutionGadget for ErrorWriteProtectionGadget { }); // current call context is readonly - cb.call_context_lookup_read(None, CallContextFieldTag::IsStatic, Word::one()); + cb.call_context_lookup_read( + None, + CallContextFieldTag::IsStatic, + Word::one::>(), + ); // constrain not root call as at least one previous staticcall preset. cb.require_zero( diff --git a/zkevm-circuits/src/evm_circuit/execution/stop.rs b/zkevm-circuits/src/evm_circuit/execution/stop.rs index 26b35745b66..8bebcbe78d6 100644 --- a/zkevm-circuits/src/evm_circuit/execution/stop.rs +++ b/zkevm-circuits/src/evm_circuit/execution/stop.rs @@ -22,7 +22,10 @@ use crate::{ }; use bus_mapping::evm::OpcodeId; use eth_types::Field; -use halo2_proofs::{circuit::Value, plonk::Error}; +use halo2_proofs::{ + circuit::Value, + plonk::{Error, Expression}, +}; #[derive(Clone, Debug)] pub(crate) struct StopGadget { @@ -63,7 +66,11 @@ impl ExecutionGadget for StopGadget { ); // Call ends with STOP must be successful - cb.call_context_lookup_read(None, CallContextFieldTag::IsSuccess, Word::one()); + 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/util/common_gadget.rs b/zkevm-circuits/src/evm_circuit/util/common_gadget.rs index 18fb9450da9..56d4ca58c24 100644 --- a/zkevm-circuits/src/evm_circuit/util/common_gadget.rs +++ b/zkevm-circuits/src/evm_circuit/util/common_gadget.rs @@ -429,7 +429,7 @@ impl TransferToGadget { receiver_address.clone(), AccountFieldTag::CodeHash, cb.empty_code_hash(), - Word::zero(), + Word::zero::>(), reversion_info, ); }, @@ -767,7 +767,7 @@ impl, const IS_SUCCESS_CAL cb.stack_push(if IS_SUCCESS_CALL { Word::from_lo_unchecked(is_success.expr()) // is_success is bool } else { - Word::zero() + Word::zero::>() }); // Recomposition of random linear combination to integer @@ -1097,7 +1097,11 @@ impl CommonErrorGadget { let rw_counter_end_of_reversion = cb.query_word_unchecked(); // rw_counter_end_of_reversion just used for read lookup, therefore skip range check // current call must be failed. - cb.call_context_lookup_read(None, CallContextFieldTag::IsSuccess, Word::zero()); + cb.call_context_lookup_read( + None, + CallContextFieldTag::IsSuccess, + Word::zero::>(), + ); cb.call_context_lookup_read( None, diff --git a/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs b/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs index ff50a6cbe1c..8b1f1e370af 100644 --- a/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs +++ b/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs @@ -165,7 +165,7 @@ pub(crate) trait ConstrainBuilderCommon { } fn require_zero_word(&mut self, name: &'static str, word: Word>) { - self.require_equal_word(name, word, Word::zero()); + self.require_equal_word(name, word, Word::zero::>()); } fn require_equal_word( @@ -865,10 +865,10 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { tx_id, account_address.compress(), 0.expr(), - Word::zero(), + Word::zero::>(), Word::from_lo_unchecked(value), Word::from_lo_unchecked(value_prev), - Word::zero(), + Word::zero::>(), ), reversion_info, ); @@ -888,10 +888,10 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { tx_id, account_address.compress(), 0.expr(), - Word::zero(), + Word::zero::>(), Word::from_lo_unchecked(value.clone()), Word::from_lo_unchecked(value), - Word::zero(), + Word::zero::>(), ), ); } @@ -914,7 +914,7 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { storage_key, value, value_prev, - Word::zero(), + Word::zero::>(), ), reversion_info, ); @@ -938,7 +938,7 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { storage_key, value.clone(), value, - Word::zero(), + Word::zero::>(), ), ); } @@ -954,10 +954,10 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { tx_id, 0.expr(), 0.expr(), - Word::zero(), + Word::zero::>(), value.clone(), value, - Word::zero(), + Word::zero::>(), ), ); } @@ -976,10 +976,10 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { tx_id, 0.expr(), 0.expr(), - Word::zero(), + Word::zero::>(), value, value_prev, - Word::zero(), + Word::zero::>(), ), reversion_info, ); @@ -1000,10 +1000,10 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { 0.expr(), account_address.compress(), field_tag.expr(), - Word::zero(), + Word::zero::>(), value.clone(), value, - Word::zero(), + Word::zero::>(), ), ); } @@ -1023,10 +1023,10 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { 0.expr(), account_address.compress(), field_tag.expr(), - Word::zero(), + Word::zero::>(), value, value_prev, - Word::zero(), + Word::zero::>(), ), reversion_info, ); @@ -1127,10 +1127,10 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { call_id.unwrap_or_else(|| self.curr.state.call_id.expr()), 0.expr(), field_tag.expr(), - Word::zero(), + Word::zero::>(), value, - Word::zero(), - Word::zero(), + Word::zero::>(), + Word::zero::>(), ), ); } @@ -1153,10 +1153,10 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { call_id.unwrap_or_else(|| self.curr.state.call_id.expr()), 0.expr(), field_tag.expr(), - Word::zero(), + Word::zero::>(), value, - Word::zero(), - Word::zero(), + Word::zero::>(), + Word::zero::>(), ), ); } @@ -1175,10 +1175,10 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { call_id.unwrap_or_else(|| self.curr.state.call_id.expr()), 0.expr(), field_tag.expr(), - Word::zero(), + Word::zero::>(), value, - Word::zero(), - Word::zero(), + Word::zero::>(), + Word::zero::>(), ), ); } @@ -1261,10 +1261,10 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { self.curr.state.call_id.expr(), self.curr.state.stack_pointer.expr() + stack_pointer_offset, 0.expr(), - Word::zero(), + Word::zero::>(), value, - Word::zero(), - Word::zero(), + Word::zero::>(), + Word::zero::>(), ), ); } @@ -1286,11 +1286,11 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { call_id.unwrap_or_else(|| self.curr.state.call_id.expr()), memory_address, 0.expr(), - Word::zero(), + Word::zero::>(), // TODO assure range check since write=true also possible Word::from_lo_unchecked(byte), - Word::zero(), - Word::zero(), + Word::zero::>(), + Word::zero::>(), ), ); } @@ -1311,10 +1311,10 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { tx_id, build_tx_log_expression(index, field_tag.expr(), log_id), 0.expr(), - Word::zero(), + Word::zero::>(), value, - Word::zero(), - Word::zero(), + Word::zero::>(), + Word::zero::>(), ), ); } @@ -1335,11 +1335,11 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { tx_id, 0.expr(), tag.expr(), - Word::zero(), + Word::zero::>(), // TODO assure range check since write=true also possible Word::from_lo_unchecked(value), - Word::zero(), - Word::zero(), + Word::zero::>(), + Word::zero::>(), ), ); } @@ -1356,10 +1356,10 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { 0.expr(), 0.expr(), 0.expr(), - Word::zero(), - Word::zero(), - Word::zero(), - Word::zero(), + Word::zero::>(), + Word::zero::>(), + Word::zero::>(), + Word::zero::>(), ), ); } diff --git a/zkevm-circuits/src/mpt_circuit.rs b/zkevm-circuits/src/mpt_circuit.rs index dfc557452e1..b70a7b5fda2 100644 --- a/zkevm-circuits/src/mpt_circuit.rs +++ b/zkevm-circuits/src/mpt_circuit.rs @@ -1,5 +1,5 @@ //! The MPT circuit implementation. -use eth_types::Field; +use eth_types::{Field, OpsIdentity}; use gadgets::{impl_expr, util::Scalar}; use halo2_proofs::{ circuit::{Layouter, SimpleFloorPlanner, Value}, @@ -208,7 +208,10 @@ pub enum FixedTableTag { } impl_expr!(FixedTableTag); -impl MPTConfig { +impl> MPTConfig +where + ::Output: Field, +{ /// Configure MPT Circuit pub fn new( meta: &mut ConstraintSystem, @@ -646,7 +649,10 @@ impl MPTConfig { /// MPT Circuit for proving the storage modification is valid. #[derive(Default)] -pub struct MPTCircuit { +pub struct MPTCircuit> +where + ::Output: Field, +{ /// MPT nodes pub nodes: Vec, /// MPT keccak_data @@ -685,7 +691,10 @@ impl MPTCircuitParams { } } -impl Circuit for MPTCircuit { +impl> Circuit for MPTCircuit +where + ::Output: Field, +{ type Config = (MPTConfig, Challenges); type FloorPlanner = SimpleFloorPlanner; type Params = MPTCircuitParams; diff --git a/zkevm-circuits/src/mpt_circuit/account_leaf.rs b/zkevm-circuits/src/mpt_circuit/account_leaf.rs index 2b16ff34c78..a60951de2cb 100644 --- a/zkevm-circuits/src/mpt_circuit/account_leaf.rs +++ b/zkevm-circuits/src/mpt_circuit/account_leaf.rs @@ -1,4 +1,4 @@ -use eth_types::{Field, U256}; +use eth_types::{Field, OpsIdentity, U256}; use gadgets::util::{pow, Scalar}; use halo2_proofs::{ circuit::Value, @@ -55,7 +55,10 @@ pub(crate) struct AccountLeafConfig { mod_extension: ModExtensionGadget, } -impl AccountLeafConfig { +impl> AccountLeafConfig +where + ::Output: Field, +{ pub fn configure( meta: &mut VirtualCells<'_, F>, cb: &mut MPTConstraintBuilder, @@ -149,10 +152,10 @@ impl AccountLeafConfig { require!(config.main_data.is_below_account => false); let mut key_rlc = vec![0.expr(); 2]; - let mut nonce = vec![Word::zero(); 2]; - let mut balance = vec![Word::zero(); 2]; - let mut storage = vec![Word::zero(); 2]; - let mut codehash = vec![Word::zero(); 2]; + let mut nonce = vec![Word::zero::>(); 2]; + let mut balance = vec![Word::zero::>(); 2]; + let mut storage = vec![Word::zero::>(); 2]; + let mut codehash = vec![Word::zero::>(); 2]; let mut leaf_no_key_rlc = vec![0.expr(); 2]; let mut leaf_no_key_rlc_mult = vec![0.expr(); 2]; let mut value_list_num_bytes = vec![0.expr(); 2]; @@ -467,7 +470,7 @@ impl AccountLeafConfig { &mut cb.base, address.clone(), proof_type.clone(), - Word::zero(), + Word::zero::>(), config.main_data.new_root.expr(), config.main_data.old_root.expr(), Word::>::new([new_value_lo, new_value_hi]), @@ -481,11 +484,11 @@ impl AccountLeafConfig { &mut cb.base, address.clone(), proof_type.clone(), - Word::zero(), + Word::zero::>(), config.main_data.new_root.expr(), config.main_data.old_root.expr(), - Word::zero(), - Word::zero(), + Word::zero::>(), + Word::zero::>(), ); }}; } elsex { @@ -499,10 +502,10 @@ impl AccountLeafConfig { &mut cb.base, address, proof_type, - Word::zero(), + Word::zero::>(), config.main_data.new_root.expr(), config.main_data.old_root.expr(), - Word::zero(), + Word::zero::>(), Word::>::new([old_value_lo, old_value_hi]), ); }}; @@ -554,10 +557,10 @@ impl AccountLeafConfig { // Key let mut key_rlc = vec![0.scalar(); 2]; - let mut nonce = vec![Word::zero_f(); 2]; - let mut balance = vec![Word::zero_f(); 2]; - let mut storage = vec![Word::zero_f(); 2]; - let mut codehash = vec![Word::zero_f(); 2]; + let mut nonce = vec![Word::zero::(); 2]; + let mut balance = vec![Word::zero::(); 2]; + let mut storage = vec![Word::zero::(); 2]; + let mut codehash = vec![Word::zero::(); 2]; let mut key_data = vec![KeyDataWitness::default(); 2]; let mut parent_data = vec![ParentDataWitness::default(); 2]; for is_s in [true, false] { @@ -727,11 +730,14 @@ impl AccountLeafConfig { } else if is_codehash_mod { (MPTProofType::CodeHashChanged, codehash) } else if is_account_delete_mod { - (MPTProofType::AccountDestructed, vec![Word::zero_f(); 2]) + (MPTProofType::AccountDestructed, vec![Word::zero::(); 2]) } else if is_non_existing_proof { - (MPTProofType::AccountDoesNotExist, vec![Word::zero_f(); 2]) + ( + MPTProofType::AccountDoesNotExist, + vec![Word::zero::(); 2], + ) } else { - (MPTProofType::Disabled, vec![Word::zero_f(); 2]) + (MPTProofType::Disabled, vec![Word::zero::(); 2]) }; if account.is_mod_extension[0] || account.is_mod_extension[1] { @@ -746,10 +752,10 @@ impl AccountLeafConfig { let mut new_value = value[false.idx()]; let mut old_value = value[true.idx()]; if parent_data[false.idx()].is_placeholder { - new_value = word::Word::zero_f(); + new_value = word::Word::zero::(); } else if is_non_existing_proof { - new_value = word::Word::zero_f(); - old_value = word::Word::zero_f(); + new_value = word::Word::zero::(); + old_value = word::Word::zero::(); } mpt_config.mpt_table.assign_cached( region, @@ -758,7 +764,7 @@ impl AccountLeafConfig { address: Value::known(from_bytes::value( &account.address.iter().cloned().rev().collect::>(), )), - storage_key: word::Word::zero_f().into_value(), + storage_key: word::Word::zero::().into_value(), proof_type: Value::known(proof_type.scalar()), new_root: main_data.new_root.into_value(), old_root: main_data.old_root.into_value(), diff --git a/zkevm-circuits/src/mpt_circuit/branch.rs b/zkevm-circuits/src/mpt_circuit/branch.rs index 5909eb0c8a2..47f109b4d69 100644 --- a/zkevm-circuits/src/mpt_circuit/branch.rs +++ b/zkevm-circuits/src/mpt_circuit/branch.rs @@ -1,4 +1,4 @@ -use eth_types::Field; +use eth_types::{Field, OpsIdentity}; use gadgets::util::Scalar; use halo2_proofs::plonk::{Error, Expression, VirtualCells}; @@ -50,7 +50,10 @@ pub(crate) struct BranchGadget { post_state: Option>, } -impl BranchGadget { +impl> BranchGadget +where + ::Output: Field, +{ #[allow(clippy::too_many_arguments)] pub fn configure( meta: &mut VirtualCells<'_, F>, @@ -299,7 +302,10 @@ impl BranchGadget { is_key_odd: &mut bool, node: &Node, rlp_values: &[RLPItemWitness], - ) -> Result<(F, F, F, [word::Word; 2], [F; 2]), Error> { + ) -> Result<(F, F, F, [word::Word; 2], [F; 2]), Error> + where + ::Output: Field, + { let branch = &node.extension_branch.clone().unwrap().branch; for is_s in [true, false] { @@ -351,7 +357,7 @@ impl BranchGadget { let key_mult_post_branch = *key_mult * mult; // Set the branch we'll take - let mut mod_node_hash_word = [word::Word::zero_f(); 2]; + let mut mod_node_hash_word = [word::Word::zero::(); 2]; let mut mod_node_hash_rlc = [0.scalar(); 2]; for is_s in [true, false] { ( diff --git a/zkevm-circuits/src/mpt_circuit/extension.rs b/zkevm-circuits/src/mpt_circuit/extension.rs index 4663bdea09c..04da2ed07f7 100644 --- a/zkevm-circuits/src/mpt_circuit/extension.rs +++ b/zkevm-circuits/src/mpt_circuit/extension.rs @@ -100,7 +100,7 @@ impl ExtensionGadget { require!((FixedTableTag::ExtOddKey.expr(), first_byte, config.is_key_part_odd.expr()) =>> @FIXED); let mut branch_rlp_rlc = vec![0.expr(); 2]; - let mut branch_rlp_word = vec![Word::zero(); 2]; + let mut branch_rlp_word = vec![Word::zero::>(); 2]; for is_s in [true, false] { // In C we have the key nibbles, we check below only for S. if is_s { diff --git a/zkevm-circuits/src/mpt_circuit/extension_branch.rs b/zkevm-circuits/src/mpt_circuit/extension_branch.rs index 50301fd4f85..873da3e0af1 100644 --- a/zkevm-circuits/src/mpt_circuit/extension_branch.rs +++ b/zkevm-circuits/src/mpt_circuit/extension_branch.rs @@ -1,4 +1,4 @@ -use eth_types::Field; +use eth_types::{Field, OpsIdentity}; use gadgets::util::Scalar; use halo2_proofs::plonk::{Error, Expression, VirtualCells}; @@ -30,7 +30,10 @@ pub(crate) struct ExtensionBranchConfig { branch: BranchGadget, } -impl ExtensionBranchConfig { +impl> ExtensionBranchConfig +where + ::Output: Field, +{ pub fn configure( meta: &mut VirtualCells<'_, F>, cb: &mut MPTConstraintBuilder, @@ -158,7 +161,7 @@ impl ExtensionBranchConfig { branch.mod_rlc[is_s.idx()].expr(), false.expr(), false.expr(), - Word::zero(), + Word::zero::>(), ); } elsex { // For the placeholder branch / extension node the values did not change, we reuse @@ -291,7 +294,7 @@ impl ExtensionBranchConfig { mod_node_hash_rlc[is_s.idx()], false, false, - Word::zero_f(), + Word::zero::(), )?; } else { KeyData::witness_store( diff --git a/zkevm-circuits/src/mpt_circuit/helpers.rs b/zkevm-circuits/src/mpt_circuit/helpers.rs index ffdd6975049..3c45224817c 100644 --- a/zkevm-circuits/src/mpt_circuit/helpers.rs +++ b/zkevm-circuits/src/mpt_circuit/helpers.rs @@ -1081,8 +1081,11 @@ impl IsPlaceholderLeafGadget { Expression::Constant(empty_hash.hi()), ]), ); - let is_nil_in_branch_at_mod_index = - IsEqualWordGadget::construct(&mut cb.base, &parent_word, &Word::zero()); + let is_nil_in_branch_at_mod_index = IsEqualWordGadget::construct( + &mut cb.base, + &parent_word, + &Word::zero::>(), + ); Self { is_empty_trie, diff --git a/zkevm-circuits/src/mpt_circuit/start.rs b/zkevm-circuits/src/mpt_circuit/start.rs index ae9d1ab40bf..7fbe0a21e02 100644 --- a/zkevm-circuits/src/mpt_circuit/start.rs +++ b/zkevm-circuits/src/mpt_circuit/start.rs @@ -15,16 +15,19 @@ use crate::{ }, util::word::Word, }; -use eth_types::Field; +use eth_types::{Field, OpsIdentity}; use gadgets::util::Scalar; -use halo2_proofs::plonk::{Error, VirtualCells}; +use halo2_proofs::plonk::{Error, Expression, VirtualCells}; #[derive(Clone, Debug, Default)] pub(crate) struct StartConfig { proof_type: Cell, } -impl StartConfig { +impl> StartConfig +where + ::Output: eth_types::Field, +{ pub fn configure( meta: &mut VirtualCells<'_, F>, cb: &mut MPTConstraintBuilder, @@ -40,7 +43,7 @@ impl StartConfig { config.proof_type = cb.query_cell(); - let mut root = vec![Word::zero(); 2]; + let mut root = vec![Word::zero::>(); 2]; for is_s in [true, false] { root[is_s.idx()] = root_items[is_s.idx()].word(); } @@ -96,7 +99,7 @@ impl StartConfig { self.proof_type .assign(region, offset, start.proof_type.scalar())?; - let mut root = vec![Word::zero_f(); 2]; + let mut root = vec![Word::zero::(); 2]; for is_s in [true, false] { root[is_s.idx()] = rlp_values[is_s.idx()].word(); } diff --git a/zkevm-circuits/src/mpt_circuit/storage_leaf.rs b/zkevm-circuits/src/mpt_circuit/storage_leaf.rs index 83ada89e271..feb5e5cc302 100644 --- a/zkevm-circuits/src/mpt_circuit/storage_leaf.rs +++ b/zkevm-circuits/src/mpt_circuit/storage_leaf.rs @@ -1,4 +1,4 @@ -use eth_types::{Field, U256}; +use eth_types::{Field, OpsIdentity, U256}; use gadgets::util::Scalar; use halo2_proofs::{ circuit::Value, @@ -54,7 +54,10 @@ pub(crate) struct StorageLeafConfig { mod_extension: ModExtensionGadget, } -impl StorageLeafConfig { +impl> StorageLeafConfig +where + ::Output: eth_types::Field, +{ pub fn configure( meta: &mut VirtualCells<'_, F>, cb: &mut MPTConstraintBuilder, @@ -104,7 +107,7 @@ impl StorageLeafConfig { require!(config.main_data.is_below_account => true); let mut key_rlc = vec![0.expr(); 2]; - let mut value_word = vec![Word::zero(); 2]; + let mut value_word = vec![Word::zero::>(); 2]; let mut value_rlp_rlc = vec![0.expr(); 2]; let mut value_rlp_rlc_mult = vec![0.expr(); 2]; @@ -191,7 +194,7 @@ impl StorageLeafConfig { // Placeholder leaves default to value `0`. ifx! {is_placeholder_leaf => { - require!(value_word[is_s.idx()] => Word::zero()); + require!(value_word[is_s.idx()] => Word::zero::>()); }} // Make sure the RLP encoding is correct. @@ -246,11 +249,11 @@ impl StorageLeafConfig { ParentData::store( cb, &mut ctx.memory[parent_memory(is_s)], - word::Word::zero(), + word::Word::zero::>(), 0.expr(), true.expr(), false.expr(), - word::Word::zero(), + word::Word::zero::>(), ); } @@ -395,7 +398,7 @@ impl StorageLeafConfig { address_item.word(), config.main_data.new_root.expr(), config.main_data.old_root.expr(), - Word::zero(), + Word::zero::>(), value_word[true.idx()].clone(), ); }}; @@ -436,7 +439,7 @@ impl StorageLeafConfig { let mut key_data = vec![KeyDataWitness::default(); 2]; let mut parent_data = vec![ParentDataWitness::default(); 2]; let mut key_rlc = vec![0.scalar(); 2]; - let mut value_word = vec![Word::zero_f(); 2]; + let mut value_word = vec![Word::zero::(); 2]; for is_s in [true, false] { self.is_mod_extension[is_s.idx()].assign( region, @@ -596,10 +599,10 @@ impl StorageLeafConfig { let mut new_value = value_word[false.idx()]; let mut old_value = value_word[true.idx()]; if parent_data[false.idx()].is_placeholder { - new_value = word::Word::zero_f(); + new_value = word::Word::zero::(); } else if is_non_existing_proof { - new_value = word::Word::zero_f(); - old_value = word::Word::zero_f(); + new_value = word::Word::zero::(); + old_value = word::Word::zero::(); } mpt_config.mpt_table.assign_cached( region, diff --git a/zkevm-circuits/src/util/word.rs b/zkevm-circuits/src/util/word.rs index 98a31fa87a0..5cc982854c4 100644 --- a/zkevm-circuits/src/util/word.rs +++ b/zkevm-circuits/src/util/word.rs @@ -4,7 +4,7 @@ // limb is 256/4 = 64 bits use bus_mapping::state_db::CodeDB; -use eth_types::{Field, ToLittleEndian, H160, H256}; +use eth_types::{Field, OpsIdentity, ToLittleEndian, H160, H256}; use gadgets::util::{not, or, Expr}; use halo2_proofs::{ circuit::{AssignedCell, Region, Value}, @@ -240,6 +240,16 @@ impl Word { pub fn map(&self, mut func: impl FnMut(T) -> T2) -> Word { Word(WordLimbs::::new([func(self.lo()), func(self.hi())])) } + + /// zero word + pub fn zero>() -> Self { + Self::new([T1::zero::(), T1::zero::()]) + } + + /// one word + pub fn one>() -> Self { + Self::new([T1::one::(), T1::zero::()]) + } } impl std::ops::Deref for Word { @@ -354,16 +364,6 @@ impl + Clone> WordExpr for Word { } impl Word { - /// zero word - pub fn zero_f() -> Self { - Self::new([F::ZERO, F::ZERO]) - } - - /// one word - pub fn one_f() -> Self { - Self::new([F::ONE, F::ZERO]) - } - /// Convert address (h160) to single field element. /// This method is Address specific pub fn compress_f(&self) -> F { @@ -376,15 +376,6 @@ impl Word> { pub fn from_lo_unchecked(lo: Expression) -> Self { Self::new([lo, 0.expr()]) } - /// zero word - pub fn zero() -> Self { - Self::new([0.expr(), 0.expr()]) - } - - /// one word - pub fn one() -> Self { - Self::new([1.expr(), 0.expr()]) - } /// select based on selector. Here assume selector is 1/0 therefore no overflow check pub fn select + Clone>(