Skip to content
This repository was archived by the owner on Apr 18, 2025. It is now read-only.
47 changes: 27 additions & 20 deletions zkevm-circuits/src/bytecode_circuit/circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ use crate::{
util::{get_push_size, Challenges, Expr, SubCircuit, SubCircuitConfig},
witness,
};
use bus_mapping::state_db::EMPTY_CODE_HASH_LE;
use eth_types::{Field, ToLittleEndian};
use bus_mapping::{state_db::EMPTY_CODE_HASH_LE, util::POSEIDON_CODE_HASH_ZERO};
use eth_types::{Field, ToLittleEndian, ToScalar, ToWord};
use gadgets::is_zero::{IsZeroChip, IsZeroConfig, IsZeroInstruction};
use halo2_proofs::{
circuit::{Layouter, Region, Value},
Expand Down Expand Up @@ -241,10 +241,14 @@ impl<F: Field> SubCircuitConfig<F> for BytecodeCircuitConfig<F> {
meta.query_advice(length, Rotation::cur()),
);

let empty_hash = rlc::expr(
&EMPTY_CODE_HASH_LE.map(|v| Expression::Constant(F::from(v as u64))),
challenges.evm_word(),
);
let empty_hash = if cfg!(feature = "poseidon-codehash") {
Expression::Constant(POSEIDON_CODE_HASH_ZERO.to_word().to_scalar().unwrap())
} else {
rlc::expr(
&EMPTY_CODE_HASH_LE.map(|v| Expression::Constant(F::from(v as u64))),
challenges.evm_word(),
)
};

cb.require_equal(
"assert cur.hash == EMPTY_HASH",
Expand Down Expand Up @@ -457,9 +461,13 @@ impl<F: Field> BytecodeCircuitConfig<F> {
last_row_offset
);

let empty_hash = challenges
.evm_word()
.map(|challenge| rlc::value(EMPTY_CODE_HASH_LE.as_ref(), challenge));
let empty_hash = challenges.evm_word().map(|challenge| {
if cfg!(feature = "poseidon-codehash") {
POSEIDON_CODE_HASH_ZERO.to_word().to_scalar().unwrap()
} else {
rlc::value(EMPTY_CODE_HASH_LE.as_ref(), challenge)
}
});

let mut is_first_time = true;
layouter.assign_region(
Expand Down Expand Up @@ -529,9 +537,13 @@ impl<F: Field> BytecodeCircuitConfig<F> {

// Code hash with challenge is calculated only using the first row of the
// bytecode (header row), the rest of the code_hash in other rows are ignored.
let code_hash = challenges
.evm_word()
.map(|challenge| rlc::value(&bytecode.rows[0].code_hash.to_le_bytes(), challenge));
let code_hash = challenges.evm_word().map(|challenge| {
if cfg!(feature = "poseidon-codehash") {
bytecode.rows[0].code_hash.to_scalar().unwrap()
} else {
rlc::value(&bytecode.rows[0].code_hash.to_le_bytes(), challenge)
}
});

for (idx, row) in bytecode.rows.iter().enumerate() {
if fail_fast && *offset > last_row_offset {
Expand Down Expand Up @@ -891,11 +903,9 @@ impl<F: Field> Circuit<F> for BytecodeCircuit<F> {
&challenges,
)?;
#[cfg(feature = "poseidon-codehash")]
config.poseidon_table.dev_load(
&mut layouter,
self.bytecodes.iter().map(|b| &b.bytes),
&challenges,
)?;
config
.poseidon_table
.dev_load(&mut layouter, self.bytecodes.iter().map(|b| &b.bytes))?;
self.synthesize_sub(&config, &challenges, &mut layouter)?;
Ok(())
}
Expand Down Expand Up @@ -1044,7 +1054,6 @@ mod tests {
}

/// Test invalid code_hash data
#[cfg(feature = "fixme")]
#[test]
fn bytecode_invalid_hash_data() {
let k = 9;
Expand Down Expand Up @@ -1088,8 +1097,6 @@ mod tests {
}

/// Test invalid byte data

#[cfg(feature = "fixme")]
#[test]
fn bytecode_invalid_byte_data() {
let k = 9;
Expand Down
34 changes: 18 additions & 16 deletions zkevm-circuits/src/bytecode_circuit/circuit/to_poseidon_hash.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
use crate::{
evm_circuit::util::{and, constraint_builder::BaseConstraintBuilder, not, or, rlc, select},
evm_circuit::util::{and, constraint_builder::BaseConstraintBuilder, not, or, select},
table::{BytecodeFieldTag, KeccakTable, PoseidonTable},
util::{Challenges, Expr, SubCircuitConfig},
};
use bus_mapping::state_db::EMPTY_CODE_HASH_LE;
use eth_types::Field;
use bus_mapping::util::POSEIDON_CODE_HASH_ZERO;
use eth_types::{Field, ToScalar, ToWord};
use gadgets::is_zero::IsZeroChip;
use halo2_proofs::{
circuit::{Layouter, Region, Value},
plonk::{Advice, Column, ConstraintSystem, Error, VirtualCells},
plonk::{Advice, Column, ConstraintSystem, Error, Expression, VirtualCells},
poly::Rotation,
};
use log::trace;
use mpt_zktrie::hash::HASHABLE_DOMAIN_SPEC;
use std::vec;

use super::{
Expand Down Expand Up @@ -52,8 +53,7 @@ impl<F: Field, const BYTES_IN_FIELD: usize> ToHashBlockCircuitConfig<F, BYTES_IN
) -> Self {
let base_conf_cl = base_conf.clone();
let bytecode_table = base_conf.bytecode_table;
// TODO: does this col still used for storing poseidon hash?
// let code_hash = bytecode_table.code_hash;
let code_hash = bytecode_table.code_hash;

let q_enable = base_conf.q_enable; // from 0 to last avaliable row

Expand Down Expand Up @@ -287,11 +287,10 @@ impl<F: Field, const BYTES_IN_FIELD: usize> ToHashBlockCircuitConfig<F, BYTES_IN
// ]))
// });

let lookup_columns = [/* code_hash, */ field_input, control_length];
let pick_hash_tbl_cols = |inp_i: usize| {
let cols =
<PoseidonTable as crate::table::LookupTable<F>>::advice_columns(&poseidon_table);
[/* cols[0], */ cols[inp_i + 1], cols[cols.len() - 2]]
[cols[0], cols[inp_i + 1], cols[cols.len() - 2]]
};

// we use a special selection exp for only 2 indexs
Expand All @@ -300,11 +299,12 @@ impl<F: Field, const BYTES_IN_FIELD: usize> ToHashBlockCircuitConfig<F, BYTES_IN
[1.expr() - field_index.clone(), field_index]
};

let domain_spec_factor = Expression::Constant(F::from_u128(HASHABLE_DOMAIN_SPEC));

// poseidon lookup:
// * PoseidonTable::INPUT_WIDTH lookups for each input field
// * PoseidonTable::INPUT_WIDTH -1 lookups for the padded zero input
// so we have 2*PoseidonTable::INPUT_WIDTH -1 lookups
#[cfg(feature = "fixme")]
for i in 0..PoseidonTable::INPUT_WIDTH {
meta.lookup_any("poseidon input", |meta| {
// Conditions:
Expand All @@ -318,9 +318,14 @@ impl<F: Field, const BYTES_IN_FIELD: usize> ToHashBlockCircuitConfig<F, BYTES_IN
// enable.clone(),
// meta.query_advice(keccak_table.is_enabled, Rotation::cur()),
// )];
let lookup_columns = [
meta.query_advice(code_hash, Rotation::cur()),
meta.query_advice(field_input, Rotation::cur()),
meta.query_advice(control_length, Rotation::cur()) * domain_spec_factor.clone(),
];
for (l_col, tbl_col) in lookup_columns.into_iter().zip(pick_hash_tbl_cols(i)) {
constraints.push((
enable.clone() * meta.query_advice(l_col, Rotation::cur()),
enable.clone() * l_col,
meta.query_advice(tbl_col, Rotation::cur()),
))
}
Expand All @@ -329,7 +334,6 @@ impl<F: Field, const BYTES_IN_FIELD: usize> ToHashBlockCircuitConfig<F, BYTES_IN
}

// the canonical form should be `for i in 1..PoseidonTable::INPUT_WIDTH{...}`
#[cfg(feature = "fixme")]
meta.lookup_any("poseidon input padding zero for final", |meta| {
// Conditions:
// - On the row with the last byte (`is_byte_to_header == 1`)
Expand All @@ -341,9 +345,9 @@ impl<F: Field, const BYTES_IN_FIELD: usize> ToHashBlockCircuitConfig<F, BYTES_IN
]);
let mut constraints = Vec::new();
for (l_exp, tbl_col) in [
// meta.query_advice(code_hash, Rotation::cur()),
meta.query_advice(code_hash, Rotation::cur()),
0.expr(),
meta.query_advice(control_length, Rotation::cur()),
meta.query_advice(control_length, Rotation::cur()) * domain_spec_factor,
]
.into_iter()
.zip(pick_hash_tbl_cols(1))
Expand Down Expand Up @@ -406,9 +410,7 @@ impl<F: Field, const BYTES_IN_FIELD: usize> ToHashBlockCircuitConfig<F, BYTES_IN
last_row_offset
);

let empty_hash = challenges
.evm_word()
.map(|challenge| rlc::value(EMPTY_CODE_HASH_LE.as_ref(), challenge));
let empty_hash = Value::known(POSEIDON_CODE_HASH_ZERO.to_word().to_scalar().unwrap());

layouter.assign_region(
|| "assign bytecode with poseidon hash extension",
Expand Down
11 changes: 10 additions & 1 deletion zkevm-circuits/src/copy_circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ use halo2_proofs::{
};

/// Encode the type `NumberOrHash` into a field element
#[allow(clippy::needless_return)]
pub fn number_or_hash_to_field<F: Field>(v: &NumberOrHash, challenge: Value<F>) -> Value<F> {
match v {
NumberOrHash::Number(n) => Value::known(F::from(*n as u64)),
Expand All @@ -52,7 +53,15 @@ pub fn number_or_hash_to_field<F: Field>(v: &NumberOrHash, challenge: Value<F>)
b.reverse();
b
};
challenge.map(|challenge| rlc::value(&le_bytes, challenge))
#[cfg(feature = "scroll")]
{
// use poseidon codehash fr
return challenge.map(|_challenge| rlc::value(&le_bytes, 0x100u64.into()));
}
#[cfg(not(feature = "scroll"))]
{
return challenge.map(|challenge| rlc::value(&le_bytes, challenge));
}
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions zkevm-circuits/src/evm_circuit/execution/balance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,9 @@ impl<F: Field> ExecutionGadget<F> for BalanceGadget<F> {

let code_hash = block.rws[step.rw_indices[5]].account_value_pair().0;
self.code_hash
.assign(region, offset, region.word_rlc(code_hash))?;
.assign(region, offset, region.code_hash(code_hash))?;
self.not_exists
.assign_value(region, offset, region.word_rlc(code_hash))?;
.assign_value(region, offset, region.code_hash(code_hash))?;
let balance = if code_hash.is_zero() {
eth_types::Word::zero()
} else {
Expand Down
6 changes: 3 additions & 3 deletions zkevm-circuits/src/evm_circuit/execution/begin_tx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -648,7 +648,7 @@ impl<F: Field> ExecutionGadget<F> for BeginTxGadget<F> {
tx_fee,
)?;
self.phase2_code_hash
.assign(region, offset, region.word_rlc(callee_code_hash))?;
.assign(region, offset, region.code_hash(callee_code_hash))?;
let untrimmed_contract_addr = {
let mut stream = RlpStream::new();
stream.begin_list(2);
Expand All @@ -668,11 +668,11 @@ impl<F: Field> ExecutionGadget<F> for BeginTxGadget<F> {
self.is_empty_code_hash.assign_value(
region,
offset,
region.word_rlc(callee_code_hash),
region.code_hash(callee_code_hash),
region.empty_code_hash_rlc(),
)?;
self.callee_not_exists
.assign_value(region, offset, region.word_rlc(callee_code_hash))?;
.assign_value(region, offset, region.code_hash(callee_code_hash))?;

let untrimmed_contract_addr = {
let mut stream = ethers_core::utils::rlp::RlpStream::new();
Expand Down
2 changes: 1 addition & 1 deletion zkevm-circuits/src/evm_circuit/execution/callop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -694,7 +694,7 @@ impl<F: Field> ExecutionGadget<F> for CallOpGadget<F> {
rd_offset,
rd_length,
step.memory_word_size(),
region.word_rlc(callee_code_hash),
region.code_hash(callee_code_hash),
)?;
self.is_warm
.assign(region, offset, Value::known(F::from(is_warm as u64)))?;
Expand Down
2 changes: 1 addition & 1 deletion zkevm-circuits/src/evm_circuit/execution/create.rs
Original file line number Diff line number Diff line change
Expand Up @@ -534,7 +534,7 @@ impl<F: Field, const IS_CREATE2: bool, const S: ExecutionState> ExecutionGadget<
let code_hash_previous = block.rws
[step.rw_indices[13 + usize::from(is_create2) + copy_rw_increase]]
.account_codehash_pair();
let code_hash_previous_rlc = region.word_rlc(code_hash_previous.0);
let code_hash_previous_rlc = region.code_hash(code_hash_previous.0);
self.code_hash_previous
.assign(region, offset, code_hash_previous_rlc)?;
self.not_address_collision
Expand Down
2 changes: 1 addition & 1 deletion zkevm-circuits/src/evm_circuit/execution/error_oog_call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ impl<F: Field> ExecutionGadget<F> for ErrorOOGCallGadget<F> {
rd_offset,
rd_length,
step.memory_word_size(),
region.word_rlc(callee_code_hash),
region.code_hash(callee_code_hash),
)?;

self.opcode
Expand Down
2 changes: 1 addition & 1 deletion zkevm-circuits/src/evm_circuit/execution/extcodecopy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ impl<F: Field> ExecutionGadget<F> for ExtcodecopyGadget<F> {

let code_hash = block.rws[step.rw_indices[8]].account_value_pair().0;
self.code_hash
.assign(region, offset, region.word_rlc(code_hash))?;
.assign(region, offset, region.code_hash(code_hash))?;

let code_size = if code_hash.is_zero() {
0
Expand Down
4 changes: 2 additions & 2 deletions zkevm-circuits/src/evm_circuit/execution/extcodesize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,9 +141,9 @@ impl<F: Field> ExecutionGadget<F> for ExtcodesizeGadget<F> {

let code_hash = block.rws[step.rw_indices[5]].account_value_pair().0;
self.code_hash
.assign(region, offset, region.word_rlc(code_hash))?;
.assign(region, offset, region.code_hash(code_hash))?;
self.not_exists
.assign_value(region, offset, region.word_rlc(code_hash))?;
.assign_value(region, offset, region.code_hash(code_hash))?;

let rw_offset = 6;
#[cfg(feature = "scroll")]
Expand Down
2 changes: 1 addition & 1 deletion zkevm-circuits/src/evm_circuit/execution/return_revert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,7 @@ impl<F: Field> ExecutionGadget<F> for ReturnRevertGadget<F> {
self.code_hash.assign(
region,
offset,
region.word_rlc(U256::from_little_endian(&code_hash)),
region.code_hash(U256::from_little_endian(&code_hash)),
)?;

// code size.
Expand Down
2 changes: 1 addition & 1 deletion zkevm-circuits/src/evm_circuit/step.rs
Original file line number Diff line number Diff line change
Expand Up @@ -588,7 +588,7 @@ impl<F: FieldExt> Step<F> {
.assign(region, offset, Value::known(F::from(step.block_num)))?;
self.state
.code_hash
.assign(region, offset, region.word_rlc(call.code_hash))?;
.assign(region, offset, region.code_hash(call.code_hash))?;
self.state.program_counter.assign(
region,
offset,
Expand Down
13 changes: 12 additions & 1 deletion zkevm-circuits/src/evm_circuit/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,14 +196,25 @@ impl<'r, 'b, F: FieldExt> CachedRegion<'r, 'b, F> {
.map(|r| rlc::value(&n.to_le_bytes(), r))
}

pub fn code_hash(&self, n: U256) -> Value<F> {
self.challenges.evm_word().map(|r| {
if cfg!(feature = "poseidon-codehash") {
// only FieldExt is not enough for ToScalar trait so we have to make workaround
rlc::value(&n.to_le_bytes(), F::from(256u64))
} else {
rlc::value(&n.to_le_bytes(), r)
}
})
}

pub fn keccak_rlc(&self, le_bytes: &[u8]) -> Value<F> {
self.challenges
.keccak_input()
.map(|r| rlc::value(le_bytes, r))
}

pub fn empty_code_hash_rlc(&self) -> Value<F> {
self.word_rlc(CodeDB::empty_code_hash().to_word())
self.code_hash(CodeDB::empty_code_hash().to_word())
}

/// Constrains a cell to have a constant value.
Expand Down
2 changes: 1 addition & 1 deletion zkevm-circuits/src/evm_circuit/util/common_gadget.rs
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ impl<F: Field> RestoreContextGadget<F> {
}

self.caller_code_hash
.assign(region, offset, region.word_rlc(caller_code_hash))?;
.assign(region, offset, region.code_hash(caller_code_hash))?;

Ok(())
}
Expand Down
13 changes: 10 additions & 3 deletions zkevm-circuits/src/evm_circuit/util/constraint_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,11 @@ use crate::{
},
util::{build_tx_log_expression, Challenges, Expr},
};
use bus_mapping::{state_db::EMPTY_CODE_HASH_LE, util::KECCAK_CODE_HASH_ZERO};
use eth_types::{Field, ToLittleEndian, ToWord};
use bus_mapping::{
state_db::EMPTY_CODE_HASH_LE,
util::{KECCAK_CODE_HASH_ZERO, POSEIDON_CODE_HASH_ZERO},
};
use eth_types::{Field, ToLittleEndian, ToScalar, ToWord};
use gadgets::util::{and, not};
use halo2_proofs::{
circuit::Value,
Expand Down Expand Up @@ -470,7 +473,11 @@ impl<'a, F: Field> ConstraintBuilder<'a, F> {
}

pub(crate) fn empty_code_hash_rlc(&self) -> Expression<F> {
self.word_rlc((*EMPTY_CODE_HASH_LE).map(|byte| byte.expr()))
if cfg!(feature = "poseidon-codehash") {
Expression::Constant(POSEIDON_CODE_HASH_ZERO.to_word().to_scalar().unwrap())
} else {
self.word_rlc((*EMPTY_CODE_HASH_LE).map(|byte| byte.expr()))
}
}

// Common
Expand Down
Loading