From 32635e7f45e4e603e117781fe03e40442758f82d Mon Sep 17 00:00:00 2001 From: Leo Lara Date: Sat, 10 Jun 2023 14:25:07 +0700 Subject: [PATCH 01/14] Bytecode Circuit: Refactor word_rlc into word lo/hi --- .../src/bytecode_circuit/circuit.rs | 66 +++++++++++++++++-- zkevm-circuits/src/table.rs | 5 +- zkevm-circuits/src/util/word.rs | 7 +- 3 files changed, 66 insertions(+), 12 deletions(-) diff --git a/zkevm-circuits/src/bytecode_circuit/circuit.rs b/zkevm-circuits/src/bytecode_circuit/circuit.rs index cd70f56a42..8b77ffba57 100644 --- a/zkevm-circuits/src/bytecode_circuit/circuit.rs +++ b/zkevm-circuits/src/bytecode_circuit/circuit.rs @@ -2,10 +2,14 @@ use crate::{ evm_circuit::util::{ and, constraint_builder::{BaseConstraintBuilder, ConstrainBuilderCommon}, - not, or, rlc, select, + from_bytes, not, or, rlc, select, }, table::{BytecodeFieldTag, BytecodeTable, KeccakTable, LookupTable}, - util::{get_push_size, Challenges, Expr, SubCircuit, SubCircuitConfig}, + util::{ + get_push_size, + word::{Word, Word32, WordExpr}, + Challenges, Expr, SubCircuit, SubCircuitConfig, + }, witness, }; use bus_mapping::state_db::EMPTY_CODE_HASH_LE; @@ -18,6 +22,7 @@ use halo2_proofs::{ }, poly::Rotation, }; +use itertools::Itertools; use log::trace; use std::vec; @@ -243,11 +248,25 @@ impl SubCircuitConfig for BytecodeCircuitConfig { challenges.evm_word(), ); + let empty_hash_word: Word> = + Word32::new(EMPTY_CODE_HASH_LE.map(|v| Expression::Constant(F::from(v as u64)))) + .to_word(); + cb.require_equal( "assert cur.hash == EMPTY_HASH", meta.query_advice(bytecode_table.code_hash, Rotation::cur()), empty_hash, ); + cb.require_equal( + "assert cur.hash == EMPTY_HASH", + meta.query_advice(bytecode_table.code_hash_word.lo(), Rotation::cur()), + empty_hash_word.lo(), + ); + cb.require_equal( + "assert cur.hash == EMPTY_HASH", + meta.query_advice(bytecode_table.code_hash_word.hi(), Rotation::cur()), + empty_hash_word.hi(), + ); cb.gate(and::expr(vec![ meta.query_fixed(q_enable, Rotation::cur()), @@ -406,9 +425,12 @@ impl SubCircuitConfig for BytecodeCircuitConfig { meta.query_advice(keccak_table.is_enabled, Rotation::cur()), )]; - for (circuit_column, table_column) in - keccak_table.match_columns(value_rlc, length, bytecode_table.code_hash) - { + for (circuit_column, table_column) in keccak_table.match_columns( + value_rlc, + length, + bytecode_table.code_hash, + bytecode_table.code_hash_word, + ) { constraints.push(( enable.clone() * meta.query_advice(circuit_column, Rotation::cur()), meta.query_advice(table_column, Rotation::cur()), @@ -480,6 +502,15 @@ impl BytecodeCircuitConfig { .evm_word() .map(|challenge| rlc::value(EMPTY_CODE_HASH_LE.as_ref(), challenge)); + let empty_hash_word = Word::new( + EMPTY_CODE_HASH_LE + .chunks(32 / 2) + .map(|bytes: &[u8]| Value::known(from_bytes::value::(bytes))) + .collect_vec() + .try_into() + .unwrap(), + ); + layouter.assign_region( || "assign bytecode", |mut region| { @@ -495,6 +526,7 @@ impl BytecodeCircuitConfig { &push_data_left_is_zero_chip, &index_length_diff_is_zero_chip, empty_hash, + empty_hash_word, &mut offset, last_row_offset, fail_fast, @@ -508,6 +540,7 @@ impl BytecodeCircuitConfig { &push_data_left_is_zero_chip, &index_length_diff_is_zero_chip, empty_hash, + empty_hash_word, idx, last_row_offset, )?; @@ -572,6 +605,7 @@ impl BytecodeCircuitConfig { push_data_left_is_zero_chip: &IsZeroChip, index_length_diff_is_zero_chip: &IsZeroChip, empty_hash: Value, + empty_hash_word: Word>, offset: &mut usize, last_row_offset: usize, fail_fast: bool, @@ -588,6 +622,16 @@ impl BytecodeCircuitConfig { let code_hash = challenges .evm_word() .map(|challenge| rlc::value(&bytecode.rows[0].code_hash.to_le_bytes(), challenge)); + let code_hash_word = Word::new( + bytecode.rows[0] + .code_hash + .to_le_bytes() + .chunks(32 / 2) + .map(|bytes| Value::known(from_bytes::value(bytes))) + .collect_vec() + .try_into() + .unwrap(), + ); for (idx, row) in bytecode.rows.iter().enumerate() { if fail_fast && *offset > last_row_offset { @@ -628,6 +672,7 @@ impl BytecodeCircuitConfig { true, *offset == last_row_offset, code_hash, + code_hash_word, row.tag, row.index, row.is_code, @@ -662,6 +707,7 @@ impl BytecodeCircuitConfig { push_data_left_is_zero_chip, index_length_diff_is_zero_chip, empty_hash, + empty_hash_word, *offset, last_row_offset, )?; @@ -677,6 +723,7 @@ impl BytecodeCircuitConfig { push_data_left_is_zero_chip: &IsZeroChip, index_length_diff_is_zero_chip: &IsZeroChip, empty_hash: Value, + empty_hash_word: Word>, offset: usize, last_row_offset: usize, ) -> Result<(), Error> { @@ -688,6 +735,7 @@ impl BytecodeCircuitConfig { offset <= last_row_offset, offset == last_row_offset, empty_hash, + empty_hash_word, F::from(BytecodeFieldTag::Header as u64), F::ZERO, F::ZERO, @@ -709,6 +757,7 @@ impl BytecodeCircuitConfig { enable: bool, last: bool, code_hash: Value, + code_hash_word: Word>, tag: F, index: F, is_code: F, @@ -776,6 +825,13 @@ impl BytecodeCircuitConfig { )?; } + code_hash_word.assign_advice( + region, + || format!("assign code_hash_word {}", offset), + self.bytecode_table.code_hash_word, + offset, + )?; + push_data_left_is_zero_chip.assign( region, offset, diff --git a/zkevm-circuits/src/table.rs b/zkevm-circuits/src/table.rs index 628f22006c..fdc2d065b3 100644 --- a/zkevm-circuits/src/table.rs +++ b/zkevm-circuits/src/table.rs @@ -5,7 +5,7 @@ use crate::{ evm_circuit::util::rlc, exp_circuit::param::{OFFSET_INCREMENT, ROWS_PER_STEP}, impl_expr, - util::{build_tx_log_address, keccak, word, Challenges}, + util::{build_tx_log_address, keccak, word::{self, Word}, Challenges}, witness::{ Block, BlockContext, Bytecode, MptUpdateRow, MptUpdates, Rw, RwMap, RwRow, Transaction, }, @@ -1032,11 +1032,14 @@ impl KeccakTable { value_rlc: Column, length: Column, code_hash: Column, + code_hash_word: Word>, ) -> Vec<(Column, Column)> { vec![ (value_rlc, self.input_rlc), (length, self.input_len), (code_hash, self.output_rlc), + (code_hash_word.lo(), self.output.lo()), + (code_hash_word.hi(), self.output.hi()), ] } } diff --git a/zkevm-circuits/src/util/word.rs b/zkevm-circuits/src/util/word.rs index fcc7467228..e7e2e33649 100644 --- a/zkevm-circuits/src/util/word.rs +++ b/zkevm-circuits/src/util/word.rs @@ -263,11 +263,6 @@ impl Word { pub fn map(&self, mut func: impl FnMut(T) -> T2) -> Word { Word(WordLimbs::::new([func(self.lo()), func(self.hi())])) } - /// Convert the word to Known Value - pub fn into_value(self) -> Word> { - let [lo, hi] = self.0.limbs; - Word::new([Value::known(lo), Value::known(hi)]) - } } impl std::ops::Deref for Word { @@ -430,7 +425,7 @@ impl WordExpr for Word> { impl WordLimbs, N1> { /// to_wordlimbs will aggregate nested expressions, which implies during expression evaluation - /// it need more recursive call. if the converted limbs word will be used in many place, + /// it need more recursive call. if the converted limbs word will be used in many places, /// consider create new low limbs word, have equality constrain, then finally use low limbs /// elsewhere. // TODO static assertion. wordaround https://github.com/nvzqz/static-assertions-rs/issues/40 From 69043d0ee5ddcfe00ee3291e88490bf1e7960f38 Mon Sep 17 00:00:00 2001 From: Leo Lara Date: Mon, 12 Jun 2023 17:35:00 +0700 Subject: [PATCH 02/14] Fix circuit --- zkevm-circuits/src/bytecode_circuit/circuit.rs | 2 +- zkevm-circuits/src/table.rs | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/zkevm-circuits/src/bytecode_circuit/circuit.rs b/zkevm-circuits/src/bytecode_circuit/circuit.rs index 8b77ffba57..c5e2e972d3 100644 --- a/zkevm-circuits/src/bytecode_circuit/circuit.rs +++ b/zkevm-circuits/src/bytecode_circuit/circuit.rs @@ -412,7 +412,7 @@ impl SubCircuitConfig for BytecodeCircuitConfig { ])) }); meta.lookup_any( - "keccak256_table_lookup(cur.value_rlc, cur.length, cur.hash)", + "keccak256_table_lookup(cur.value_rlc, cur.length, cur.hash, cur.hash_word)", |meta| { let enable = and::expr(vec![ meta.query_fixed(q_enable, Rotation::cur()), diff --git a/zkevm-circuits/src/table.rs b/zkevm-circuits/src/table.rs index fdc2d065b3..a4f106527e 100644 --- a/zkevm-circuits/src/table.rs +++ b/zkevm-circuits/src/table.rs @@ -5,7 +5,11 @@ use crate::{ evm_circuit::util::rlc, exp_circuit::param::{OFFSET_INCREMENT, ROWS_PER_STEP}, impl_expr, - util::{build_tx_log_address, keccak, word::{self, Word}, Challenges}, + util::{ + build_tx_log_address, keccak, + word::{self, Word}, + Challenges, + }, witness::{ Block, BlockContext, Bytecode, MptUpdateRow, MptUpdates, Rw, RwMap, RwRow, Transaction, }, @@ -710,7 +714,7 @@ impl BytecodeTable { pub fn construct(meta: &mut ConstraintSystem) -> Self { let [tag, index, is_code, value] = array::from_fn(|_| meta.advice_column()); let code_hash_word = word::Word::new([meta.advice_column(), meta.advice_column()]); - let code_hash = meta.advice_column(); + let code_hash = meta.advice_column_in(SecondPhase); Self { code_hash_word, code_hash, From 0ce0a6d253ffff48c9671b3bbed501d823326da1 Mon Sep 17 00:00:00 2001 From: Leo Lara Date: Sat, 17 Jun 2023 17:35:59 +0700 Subject: [PATCH 03/14] Add empty_hash_word as a global function --- .../src/bytecode_circuit/circuit.rs | 20 +++---------------- zkevm-circuits/src/util/word.rs | 12 +++++++++++ 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/zkevm-circuits/src/bytecode_circuit/circuit.rs b/zkevm-circuits/src/bytecode_circuit/circuit.rs index c5e2e972d3..22055375a5 100644 --- a/zkevm-circuits/src/bytecode_circuit/circuit.rs +++ b/zkevm-circuits/src/bytecode_circuit/circuit.rs @@ -2,12 +2,12 @@ use crate::{ evm_circuit::util::{ and, constraint_builder::{BaseConstraintBuilder, ConstrainBuilderCommon}, - from_bytes, not, or, rlc, select, + not, or, rlc, select, }, table::{BytecodeFieldTag, BytecodeTable, KeccakTable, LookupTable}, util::{ get_push_size, - word::{Word, Word32, WordExpr}, + word::{empty_code_hash_word_value, Word, Word32, WordExpr}, Challenges, Expr, SubCircuit, SubCircuitConfig, }, witness, @@ -502,15 +502,6 @@ impl BytecodeCircuitConfig { .evm_word() .map(|challenge| rlc::value(EMPTY_CODE_HASH_LE.as_ref(), challenge)); - let empty_hash_word = Word::new( - EMPTY_CODE_HASH_LE - .chunks(32 / 2) - .map(|bytes: &[u8]| Value::known(from_bytes::value::(bytes))) - .collect_vec() - .try_into() - .unwrap(), - ); - layouter.assign_region( || "assign bytecode", |mut region| { @@ -526,7 +517,6 @@ impl BytecodeCircuitConfig { &push_data_left_is_zero_chip, &index_length_diff_is_zero_chip, empty_hash, - empty_hash_word, &mut offset, last_row_offset, fail_fast, @@ -540,7 +530,6 @@ impl BytecodeCircuitConfig { &push_data_left_is_zero_chip, &index_length_diff_is_zero_chip, empty_hash, - empty_hash_word, idx, last_row_offset, )?; @@ -605,7 +594,6 @@ impl BytecodeCircuitConfig { push_data_left_is_zero_chip: &IsZeroChip, index_length_diff_is_zero_chip: &IsZeroChip, empty_hash: Value, - empty_hash_word: Word>, offset: &mut usize, last_row_offset: usize, fail_fast: bool, @@ -707,7 +695,6 @@ impl BytecodeCircuitConfig { push_data_left_is_zero_chip, index_length_diff_is_zero_chip, empty_hash, - empty_hash_word, *offset, last_row_offset, )?; @@ -723,7 +710,6 @@ impl BytecodeCircuitConfig { push_data_left_is_zero_chip: &IsZeroChip, index_length_diff_is_zero_chip: &IsZeroChip, empty_hash: Value, - empty_hash_word: Word>, offset: usize, last_row_offset: usize, ) -> Result<(), Error> { @@ -735,7 +721,7 @@ impl BytecodeCircuitConfig { offset <= last_row_offset, offset == last_row_offset, empty_hash, - empty_hash_word, + empty_code_hash_word_value(), F::from(BytecodeFieldTag::Header as u64), F::ZERO, F::ZERO, diff --git a/zkevm-circuits/src/util/word.rs b/zkevm-circuits/src/util/word.rs index e7e2e33649..f1f4367212 100644 --- a/zkevm-circuits/src/util/word.rs +++ b/zkevm-circuits/src/util/word.rs @@ -3,6 +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 bus_mapping::state_db::EMPTY_CODE_HASH_LE; use eth_types::{Field, ToLittleEndian, H160}; use gadgets::util::{not, or, Expr}; use halo2_proofs::{ @@ -478,4 +479,15 @@ impl From> for Word32Cell { } } +pub fn empty_code_hash_word_value() -> Word> { + Word::new( + EMPTY_CODE_HASH_LE + .chunks(32 / 2) + .map(|bytes: &[u8]| Value::known(from_bytes::value(bytes))) + .collect_vec() + .try_into() + .unwrap(), + ) +} + // TODO unittest From 5b09d835cae7973948cd2332281f930a60c532b8 Mon Sep 17 00:00:00 2001 From: Leo Lara Date: Sat, 17 Jun 2023 17:39:14 +0700 Subject: [PATCH 04/14] Simplify code --- zkevm-circuits/src/bytecode_circuit/circuit.rs | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/zkevm-circuits/src/bytecode_circuit/circuit.rs b/zkevm-circuits/src/bytecode_circuit/circuit.rs index 22055375a5..cd2b9e4301 100644 --- a/zkevm-circuits/src/bytecode_circuit/circuit.rs +++ b/zkevm-circuits/src/bytecode_circuit/circuit.rs @@ -610,16 +610,7 @@ impl BytecodeCircuitConfig { let code_hash = challenges .evm_word() .map(|challenge| rlc::value(&bytecode.rows[0].code_hash.to_le_bytes(), challenge)); - let code_hash_word = Word::new( - bytecode.rows[0] - .code_hash - .to_le_bytes() - .chunks(32 / 2) - .map(|bytes| Value::known(from_bytes::value(bytes))) - .collect_vec() - .try_into() - .unwrap(), - ); + let code_hash_word = Word::from(bytecode.rows[0].code_hash).into_value(); for (idx, row) in bytecode.rows.iter().enumerate() { if fail_fast && *offset > last_row_offset { From 84c48c713723c9424bd0d54e836d86ae4b464261 Mon Sep 17 00:00:00 2001 From: Leo Lara Date: Sat, 17 Jun 2023 17:47:24 +0700 Subject: [PATCH 05/14] Remove lookup to output_rlc in keccak --- zkevm-circuits/src/bytecode_circuit/circuit.rs | 11 ++++------- zkevm-circuits/src/table.rs | 2 -- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/zkevm-circuits/src/bytecode_circuit/circuit.rs b/zkevm-circuits/src/bytecode_circuit/circuit.rs index cd2b9e4301..97acdb8573 100644 --- a/zkevm-circuits/src/bytecode_circuit/circuit.rs +++ b/zkevm-circuits/src/bytecode_circuit/circuit.rs @@ -412,7 +412,7 @@ impl SubCircuitConfig for BytecodeCircuitConfig { ])) }); meta.lookup_any( - "keccak256_table_lookup(cur.value_rlc, cur.length, cur.hash, cur.hash_word)", + "keccak256_table_lookup(cur.value_rlc, cur.length, cur.hash_word)", |meta| { let enable = and::expr(vec![ meta.query_fixed(q_enable, Rotation::cur()), @@ -425,12 +425,9 @@ impl SubCircuitConfig for BytecodeCircuitConfig { meta.query_advice(keccak_table.is_enabled, Rotation::cur()), )]; - for (circuit_column, table_column) in keccak_table.match_columns( - value_rlc, - length, - bytecode_table.code_hash, - bytecode_table.code_hash_word, - ) { + for (circuit_column, table_column) in + keccak_table.match_columns(value_rlc, length, bytecode_table.code_hash_word) + { constraints.push(( enable.clone() * meta.query_advice(circuit_column, Rotation::cur()), meta.query_advice(table_column, Rotation::cur()), diff --git a/zkevm-circuits/src/table.rs b/zkevm-circuits/src/table.rs index a4f106527e..83c7ccc4c7 100644 --- a/zkevm-circuits/src/table.rs +++ b/zkevm-circuits/src/table.rs @@ -1035,13 +1035,11 @@ impl KeccakTable { &self, value_rlc: Column, length: Column, - code_hash: Column, code_hash_word: Word>, ) -> Vec<(Column, Column)> { vec![ (value_rlc, self.input_rlc), (length, self.input_len), - (code_hash, self.output_rlc), (code_hash_word.lo(), self.output.lo()), (code_hash_word.hi(), self.output.hi()), ] From 66c3d9c10950a851efc00358973b95a29783e68a Mon Sep 17 00:00:00 2001 From: Leo Lara Date: Sat, 17 Jun 2023 18:50:14 +0700 Subject: [PATCH 06/14] Remove code_hash(rlc) and rename code_hash_word to code_hash --- .../src/bytecode_circuit/circuit.rs | 94 +++++++------------ zkevm-circuits/src/table.rs | 12 +-- zkevm-circuits/src/util/word.rs | 1 + 3 files changed, 39 insertions(+), 68 deletions(-) diff --git a/zkevm-circuits/src/bytecode_circuit/circuit.rs b/zkevm-circuits/src/bytecode_circuit/circuit.rs index 97acdb8573..ef6db4a0e7 100644 --- a/zkevm-circuits/src/bytecode_circuit/circuit.rs +++ b/zkevm-circuits/src/bytecode_circuit/circuit.rs @@ -2,7 +2,7 @@ use crate::{ evm_circuit::util::{ and, constraint_builder::{BaseConstraintBuilder, ConstrainBuilderCommon}, - not, or, rlc, select, + not, or, select, }, table::{BytecodeFieldTag, BytecodeTable, KeccakTable, LookupTable}, util::{ @@ -13,7 +13,7 @@ use crate::{ witness, }; use bus_mapping::state_db::EMPTY_CODE_HASH_LE; -use eth_types::{Field, ToLittleEndian}; +use eth_types::Field; use gadgets::is_zero::{IsZeroChip, IsZeroConfig, IsZeroInstruction}; use halo2_proofs::{ circuit::{Layouter, Region, Value}, @@ -243,29 +243,17 @@ impl SubCircuitConfig for BytecodeCircuitConfig { 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_word: Word> = Word32::new(EMPTY_CODE_HASH_LE.map(|v| Expression::Constant(F::from(v as u64)))) .to_word(); - cb.require_equal( - "assert cur.hash == EMPTY_HASH", - meta.query_advice(bytecode_table.code_hash, Rotation::cur()), - empty_hash, - ); - cb.require_equal( + cb.require_equal_word( "assert cur.hash == EMPTY_HASH", - meta.query_advice(bytecode_table.code_hash_word.lo(), Rotation::cur()), - empty_hash_word.lo(), - ); - cb.require_equal( - "assert cur.hash == EMPTY_HASH", - meta.query_advice(bytecode_table.code_hash_word.hi(), Rotation::cur()), - empty_hash_word.hi(), + Word::new([ + meta.query_advice(bytecode_table.code_hash.lo(), Rotation::cur()), + meta.query_advice(bytecode_table.code_hash.hi(), Rotation::cur()), + ]), + empty_hash_word, ); cb.gate(and::expr(vec![ @@ -303,10 +291,16 @@ impl SubCircuitConfig for BytecodeCircuitConfig { 1.expr(), ); - cb.require_equal( + cb.require_equal_word( "next.hash == cur.hash", - meta.query_advice(bytecode_table.code_hash, Rotation::next()), - meta.query_advice(bytecode_table.code_hash, Rotation::cur()), + Word::new([ + meta.query_advice(bytecode_table.code_hash.lo(), Rotation::next()), + meta.query_advice(bytecode_table.code_hash.hi(), Rotation::next()), + ]), + Word::new([ + meta.query_advice(bytecode_table.code_hash.lo(), Rotation::cur()), + meta.query_advice(bytecode_table.code_hash.hi(), Rotation::cur()), + ]), ); cb.require_equal( @@ -346,10 +340,16 @@ impl SubCircuitConfig for BytecodeCircuitConfig { meta.query_advice(bytecode_table.index, Rotation::cur()) + 1.expr(), ); - cb.require_equal( + cb.require_equal_word( "next.hash == cur.hash", - meta.query_advice(bytecode_table.code_hash, Rotation::next()), - meta.query_advice(bytecode_table.code_hash, Rotation::cur()), + Word::new([ + meta.query_advice(bytecode_table.code_hash.lo(), Rotation::next()), + meta.query_advice(bytecode_table.code_hash.hi(), Rotation::next()), + ]), + Word::new([ + meta.query_advice(bytecode_table.code_hash.lo(), Rotation::cur()), + meta.query_advice(bytecode_table.code_hash.hi(), Rotation::cur()), + ]), ); cb.require_equal( @@ -426,7 +426,7 @@ impl SubCircuitConfig for BytecodeCircuitConfig { )]; for (circuit_column, table_column) in - keccak_table.match_columns(value_rlc, length, bytecode_table.code_hash_word) + keccak_table.match_columns(value_rlc, length, bytecode_table.code_hash) { constraints.push(( enable.clone() * meta.query_advice(circuit_column, Rotation::cur()), @@ -495,10 +495,6 @@ impl BytecodeCircuitConfig { last_row_offset ); - let empty_hash = challenges - .evm_word() - .map(|challenge| rlc::value(EMPTY_CODE_HASH_LE.as_ref(), challenge)); - layouter.assign_region( || "assign bytecode", |mut region| { @@ -513,7 +509,6 @@ impl BytecodeCircuitConfig { challenges, &push_data_left_is_zero_chip, &index_length_diff_is_zero_chip, - empty_hash, &mut offset, last_row_offset, fail_fast, @@ -526,7 +521,6 @@ impl BytecodeCircuitConfig { &mut region, &push_data_left_is_zero_chip, &index_length_diff_is_zero_chip, - empty_hash, idx, last_row_offset, )?; @@ -562,13 +556,7 @@ impl BytecodeCircuitConfig { value_rlc = challenges.keccak_input().map(|_| F::ZERO); } - let code_hash = challenges - .evm_word() - .map(|challenge| rlc::value(&row.code_hash.to_le_bytes(), challenge)); - for (name, column, value) in [ - ("code_hash", self.bytecode_table.code_hash, code_hash), - ("value_rlc", self.value_rlc, value_rlc), - ] { + for (name, column, value) in [("value_rlc", self.value_rlc, value_rlc)] { region.assign_advice( || format!("assign {} {}", name, offset), column, @@ -590,7 +578,6 @@ impl BytecodeCircuitConfig { challenges: &Challenges>, push_data_left_is_zero_chip: &IsZeroChip, index_length_diff_is_zero_chip: &IsZeroChip, - empty_hash: Value, offset: &mut usize, last_row_offset: usize, fail_fast: bool, @@ -602,12 +589,7 @@ impl BytecodeCircuitConfig { let mut value_rlc = challenges.keccak_input().map(|_| F::ZERO); let length = F::from(bytecode.bytes.len() as u64); - // 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_word = Word::from(bytecode.rows[0].code_hash).into_value(); + let code_hash = Word::from(bytecode.rows[0].code_hash).into_value(); for (idx, row) in bytecode.rows.iter().enumerate() { if fail_fast && *offset > last_row_offset { @@ -648,7 +630,6 @@ impl BytecodeCircuitConfig { true, *offset == last_row_offset, code_hash, - code_hash_word, row.tag, row.index, row.is_code, @@ -682,7 +663,6 @@ impl BytecodeCircuitConfig { region, push_data_left_is_zero_chip, index_length_diff_is_zero_chip, - empty_hash, *offset, last_row_offset, )?; @@ -697,7 +677,6 @@ impl BytecodeCircuitConfig { region: &mut Region<'_, F>, push_data_left_is_zero_chip: &IsZeroChip, index_length_diff_is_zero_chip: &IsZeroChip, - empty_hash: Value, offset: usize, last_row_offset: usize, ) -> Result<(), Error> { @@ -708,7 +687,6 @@ impl BytecodeCircuitConfig { offset, offset <= last_row_offset, offset == last_row_offset, - empty_hash, empty_code_hash_word_value(), F::from(BytecodeFieldTag::Header as u64), F::ZERO, @@ -730,8 +708,7 @@ impl BytecodeCircuitConfig { offset: usize, enable: bool, last: bool, - code_hash: Value, - code_hash_word: Word>, + code_hash: Word>, tag: F, index: F, is_code: F, @@ -787,10 +764,7 @@ impl BytecodeCircuitConfig { || Value::known(value), )?; } - for (name, column, value) in [ - ("code_hash", self.bytecode_table.code_hash, code_hash), - ("value_rlc", self.value_rlc, value_rlc), - ] { + for (name, column, value) in [("value_rlc", self.value_rlc, value_rlc)] { region.assign_advice( || format!("assign {} {}", name, offset), column, @@ -799,10 +773,10 @@ impl BytecodeCircuitConfig { )?; } - code_hash_word.assign_advice( + code_hash.assign_advice( region, - || format!("assign code_hash_word {}", offset), - self.bytecode_table.code_hash_word, + || format!("assign code_hash {}", offset), + self.bytecode_table.code_hash, offset, )?; diff --git a/zkevm-circuits/src/table.rs b/zkevm-circuits/src/table.rs index 83c7ccc4c7..0dfdd6f7cc 100644 --- a/zkevm-circuits/src/table.rs +++ b/zkevm-circuits/src/table.rs @@ -695,10 +695,7 @@ impl_expr!(BytecodeFieldTag); #[derive(Clone, Debug)] pub struct BytecodeTable { /// Code Hash - pub code_hash_word: word::Word>, - #[deprecated] - /// Code Hash - pub code_hash: Column, + pub code_hash: word::Word>, /// Tag pub tag: Column, /// Index @@ -716,8 +713,7 @@ impl BytecodeTable { let code_hash_word = word::Word::new([meta.advice_column(), meta.advice_column()]); let code_hash = meta.advice_column_in(SecondPhase); Self { - code_hash_word, - code_hash, + code_hash: code_hash_word, tag, index, is_code, @@ -771,8 +767,8 @@ impl BytecodeTable { impl LookupTable for BytecodeTable { fn columns(&self) -> Vec> { vec![ - self.code_hash_word.lo().into(), - self.code_hash_word.hi().into(), + self.code_hash.lo().into(), + self.code_hash.hi().into(), self.tag.into(), self.index.into(), self.is_code.into(), diff --git a/zkevm-circuits/src/util/word.rs b/zkevm-circuits/src/util/word.rs index f1f4367212..6be4d6b326 100644 --- a/zkevm-circuits/src/util/word.rs +++ b/zkevm-circuits/src/util/word.rs @@ -479,6 +479,7 @@ impl From> for Word32Cell { } } +/// Return the hash of the empty code as a Word> pub fn empty_code_hash_word_value() -> Word> { Word::new( EMPTY_CODE_HASH_LE From afa57610c075ad96178f0ac34c155101728de05a Mon Sep 17 00:00:00 2001 From: Leo Lara Date: Sun, 18 Jun 2023 19:29:42 +0700 Subject: [PATCH 07/14] Cleaning --- zkevm-circuits/src/bytecode_circuit/circuit.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/zkevm-circuits/src/bytecode_circuit/circuit.rs b/zkevm-circuits/src/bytecode_circuit/circuit.rs index 001a247416..a491fd1598 100644 --- a/zkevm-circuits/src/bytecode_circuit/circuit.rs +++ b/zkevm-circuits/src/bytecode_circuit/circuit.rs @@ -14,7 +14,7 @@ use crate::{ }; use bus_mapping::state_db::EMPTY_CODE_HASH_LE; use eth_types::Field; -use gadgets::is_zero::{IsZeroChip, IsZeroConfig, IsZeroInstruction}; +use gadgets::is_zero::{IsZeroChip, IsZeroInstruction}; use halo2_proofs::{ circuit::{Layouter, Region, Value}, plonk::{ @@ -22,7 +22,6 @@ use halo2_proofs::{ }, poly::Rotation, }; -use itertools::Itertools; use log::trace; use std::vec; @@ -534,7 +533,7 @@ impl BytecodeCircuitConfig { // Padding for idx in offset..=last_row_offset { - self.set_padding_row(&mut region, challenges, idx, last_row_offset)?; + self.set_padding_row(&mut region, idx, last_row_offset)?; } // Overwrite the witness assignment by using the values in the `overwrite` @@ -651,7 +650,7 @@ impl BytecodeCircuitConfig { push_data_left = next_push_data_left } if *offset == last_row_offset { - self.set_padding_row(region, challenges, *offset, last_row_offset)?; + self.set_padding_row(region, *offset, last_row_offset)?; } } @@ -661,7 +660,6 @@ impl BytecodeCircuitConfig { fn set_padding_row( &self, region: &mut Region<'_, F>, - challenges: &Challenges>, offset: usize, last_row_offset: usize, ) -> Result<(), Error> { From b38d24e575d05ab78d9ef4aaff9207ec5d71eeb7 Mon Sep 17 00:00:00 2001 From: Leo Lara Date: Mon, 19 Jun 2023 06:32:01 +0700 Subject: [PATCH 08/14] clippy --- .../src/bytecode_circuit/circuit.rs | 29 +++++++++---------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/zkevm-circuits/src/bytecode_circuit/circuit.rs b/zkevm-circuits/src/bytecode_circuit/circuit.rs index a491fd1598..89b81e1a23 100644 --- a/zkevm-circuits/src/bytecode_circuit/circuit.rs +++ b/zkevm-circuits/src/bytecode_circuit/circuit.rs @@ -566,14 +566,12 @@ impl BytecodeCircuitConfig { value_rlc = challenges.keccak_input().map(|_| F::ZERO); } - for (name, column, value) in [("value_rlc", self.value_rlc, value_rlc)] { - region.assign_advice( - || format!("assign {} {}", name, offset), - column, - offset, - || value, - )?; - } + region.assign_advice( + || format!("assign value_rlc {}", offset), + self.value_rlc, + offset, + || value_rlc, + )?; } Ok(()) }, @@ -723,14 +721,13 @@ impl BytecodeCircuitConfig { || Value::known(value), )?; } - for (name, column, value) in [("value_rlc", self.value_rlc, row.value_rlc)] { - region.assign_advice( - || format!("assign {} {}", name, offset), - column, - offset, - || value, - )?; - } + + region.assign_advice( + || format!("assign value_rlc {}", offset), + self.value_rlc, + offset, + || row.value_rlc, + )?; row.code_hash.assign_advice( region, From 0d46956d32ce8b626b457372569e0e7ba5f9f8c2 Mon Sep 17 00:00:00 2001 From: Leo Lara Date: Mon, 19 Jun 2023 12:22:01 +0700 Subject: [PATCH 09/14] Simplify empty_code_hash_word_value --- bus-mapping/src/state_db.rs | 2 +- zkevm-circuits/src/util/word.rs | 23 ++++++++++++++--------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/bus-mapping/src/state_db.rs b/bus-mapping/src/state_db.rs index 84bf451109..3ca3f762d0 100644 --- a/bus-mapping/src/state_db.rs +++ b/bus-mapping/src/state_db.rs @@ -9,7 +9,7 @@ use std::collections::{HashMap, HashSet}; lazy_static! { static ref ACCOUNT_ZERO: Account = Account::zero(); /// Hash value for empty code hash. - static ref EMPTY_CODE_HASH: Hash = CodeDB::hash(&[]); + pub static ref EMPTY_CODE_HASH: Hash = CodeDB::hash(&[]); /// bytes of empty code hash, in little endian order. pub static ref EMPTY_CODE_HASH_LE: [u8; 32] = { let mut bytes = EMPTY_CODE_HASH.to_fixed_bytes(); diff --git a/zkevm-circuits/src/util/word.rs b/zkevm-circuits/src/util/word.rs index ba84ca1d20..8ebd9d3f15 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 bus_mapping::state_db::EMPTY_CODE_HASH_LE; +use bus_mapping::state_db::{EMPTY_CODE_HASH, EMPTY_CODE_HASH_LE}; use eth_types::{Field, ToLittleEndian, H160}; use gadgets::util::{not, or, Expr}; use halo2_proofs::{ @@ -324,6 +324,18 @@ impl From for Word { } } +impl From for Word { + /// Construct the word from eth_types::Hash + fn from(value: eth_types::Hash) -> Self { + let mut bytes = *value.as_fixed_bytes(); + bytes.reverse(); + Word::new([ + from_bytes::value(&bytes[..N_BYTES_HALF_WORD]), + from_bytes::value(&bytes[N_BYTES_HALF_WORD..]), + ]) + } +} + impl Word> { /// Assign low 128 bits for the word pub fn assign_lo( @@ -481,14 +493,7 @@ impl From> for Word32Cell { /// Return the hash of the empty code as a Word> pub fn empty_code_hash_word_value() -> Word> { - Word::new( - EMPTY_CODE_HASH_LE - .chunks(32 / 2) - .map(|bytes: &[u8]| Value::known(from_bytes::value(bytes))) - .collect_vec() - .try_into() - .unwrap(), - ) + Word::from(*EMPTY_CODE_HASH).into_value() } // TODO unittest From 278d706e8e866d71bf0a729b5a5dbd1edd199d15 Mon Sep 17 00:00:00 2001 From: Leo Lara Date: Mon, 19 Jun 2023 12:36:03 +0700 Subject: [PATCH 10/14] clean --- zkevm-circuits/src/util/word.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zkevm-circuits/src/util/word.rs b/zkevm-circuits/src/util/word.rs index 8ebd9d3f15..00d2e38c5a 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 bus_mapping::state_db::{EMPTY_CODE_HASH, EMPTY_CODE_HASH_LE}; +use bus_mapping::state_db::EMPTY_CODE_HASH; use eth_types::{Field, ToLittleEndian, H160}; use gadgets::util::{not, or, Expr}; use halo2_proofs::{ From 75741d255a8ad1b0b134c97db5847459cab12b5a Mon Sep 17 00:00:00 2001 From: Leo Lara Date: Tue, 20 Jun 2023 18:01:04 +0800 Subject: [PATCH 11/14] Improve code readabiliy --- .../src/bytecode_circuit/circuit.rs | 28 ++++--------------- zkevm-circuits/src/util/word.rs | 28 ++++++++++++++++++- 2 files changed, 33 insertions(+), 23 deletions(-) diff --git a/zkevm-circuits/src/bytecode_circuit/circuit.rs b/zkevm-circuits/src/bytecode_circuit/circuit.rs index 89b81e1a23..6cad140b4c 100644 --- a/zkevm-circuits/src/bytecode_circuit/circuit.rs +++ b/zkevm-circuits/src/bytecode_circuit/circuit.rs @@ -277,15 +277,11 @@ impl SubCircuitConfig for BytecodeCircuitConfig { ); let empty_hash_word: Word> = - Word32::new(EMPTY_CODE_HASH_LE.map(|v| Expression::Constant(F::from(v as u64)))) - .to_word(); + Word32::new(*EMPTY_CODE_HASH_LE).to_expr().to_word(); cb.require_equal_word( "assert cur.hash == EMPTY_HASH", - Word::new([ - meta.query_advice(bytecode_table.code_hash.lo(), Rotation::cur()), - meta.query_advice(bytecode_table.code_hash.hi(), Rotation::cur()), - ]), + bytecode_table.code_hash.query(meta, Rotation::cur()), empty_hash_word, ); @@ -326,14 +322,8 @@ impl SubCircuitConfig for BytecodeCircuitConfig { cb.require_equal_word( "next.hash == cur.hash", - Word::new([ - meta.query_advice(bytecode_table.code_hash.lo(), Rotation::next()), - meta.query_advice(bytecode_table.code_hash.hi(), Rotation::next()), - ]), - Word::new([ - meta.query_advice(bytecode_table.code_hash.lo(), Rotation::cur()), - meta.query_advice(bytecode_table.code_hash.hi(), Rotation::cur()), - ]), + bytecode_table.code_hash.query(meta, Rotation::next()), + bytecode_table.code_hash.query(meta, Rotation::cur()), ); cb.require_equal( @@ -375,14 +365,8 @@ impl SubCircuitConfig for BytecodeCircuitConfig { cb.require_equal_word( "next.hash == cur.hash", - Word::new([ - meta.query_advice(bytecode_table.code_hash.lo(), Rotation::next()), - meta.query_advice(bytecode_table.code_hash.hi(), Rotation::next()), - ]), - Word::new([ - meta.query_advice(bytecode_table.code_hash.lo(), Rotation::cur()), - meta.query_advice(bytecode_table.code_hash.hi(), Rotation::cur()), - ]), + bytecode_table.code_hash.query(meta, Rotation::next()), + bytecode_table.code_hash.query(meta, Rotation::cur()), ); cb.require_equal( diff --git a/zkevm-circuits/src/util/word.rs b/zkevm-circuits/src/util/word.rs index 00d2e38c5a..f97bd5e2a4 100644 --- a/zkevm-circuits/src/util/word.rs +++ b/zkevm-circuits/src/util/word.rs @@ -8,7 +8,8 @@ use eth_types::{Field, ToLittleEndian, H160}; use gadgets::util::{not, or, Expr}; use halo2_proofs::{ circuit::{AssignedCell, Region, Value}, - plonk::{Advice, Column, Error, Expression}, + plonk::{Advice, Column, Error, Expression, VirtualCells}, + poly::Rotation, }; use itertools::Itertools; @@ -47,6 +48,24 @@ impl WordLimbs { } } +impl WordLimbs, N> { + /// Query advice of WordLibs of columns advice + pub fn query( + &self, + meta: &mut VirtualCells, + at: Rotation, + ) -> WordLimbs, N> { + WordLimbs::new(self.limbs.map(|column| meta.query_advice(column, at))) + } +} + +impl WordLimbs { + /// Convert WordLimbs of u8 to WordLimbs of expressions + pub fn to_expr(&self) -> WordLimbs, N> { + WordLimbs::new(self.limbs.map(|v| Expression::Constant(F::from(v as u64)))) + } +} + impl Default for WordLimbs { fn default() -> Self { Self { @@ -372,6 +391,13 @@ impl Word> { } } +impl Word> { + /// Query advice of Word of columns advice + pub fn query(&self, meta: &mut VirtualCells, at: Rotation) -> Word> { + self.0.query(meta, at).to_word() + } +} + impl WordExpr for Word> { fn to_word(&self) -> Word> { self.word_expr().to_word() From 9491aa7b648198251be3faa751d6c108547ee54c Mon Sep 17 00:00:00 2001 From: Leo Lara Date: Tue, 20 Jun 2023 22:30:10 +0800 Subject: [PATCH 12/14] Make EMPTY_CODE_HASH private --- bus-mapping/src/state_db.rs | 2 +- zkevm-circuits/src/util/word.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bus-mapping/src/state_db.rs b/bus-mapping/src/state_db.rs index 3ca3f762d0..84bf451109 100644 --- a/bus-mapping/src/state_db.rs +++ b/bus-mapping/src/state_db.rs @@ -9,7 +9,7 @@ use std::collections::{HashMap, HashSet}; lazy_static! { static ref ACCOUNT_ZERO: Account = Account::zero(); /// Hash value for empty code hash. - pub static ref EMPTY_CODE_HASH: Hash = CodeDB::hash(&[]); + static ref EMPTY_CODE_HASH: Hash = CodeDB::hash(&[]); /// bytes of empty code hash, in little endian order. pub static ref EMPTY_CODE_HASH_LE: [u8; 32] = { let mut bytes = EMPTY_CODE_HASH.to_fixed_bytes(); diff --git a/zkevm-circuits/src/util/word.rs b/zkevm-circuits/src/util/word.rs index f97bd5e2a4..6b13f1a5c3 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 bus_mapping::state_db::EMPTY_CODE_HASH; +use bus_mapping::state_db::CodeDB; use eth_types::{Field, ToLittleEndian, H160}; use gadgets::util::{not, or, Expr}; use halo2_proofs::{ @@ -519,7 +519,7 @@ impl From> for Word32Cell { /// Return the hash of the empty code as a Word> pub fn empty_code_hash_word_value() -> Word> { - Word::from(*EMPTY_CODE_HASH).into_value() + Word::from(CodeDB::empty_code_hash()).into_value() } // TODO unittest From 33a0c1cfd849c7f2aa4ad13fe1ef20ed355151aa Mon Sep 17 00:00:00 2001 From: Leo Lara Date: Wed, 21 Jun 2023 11:29:54 +0800 Subject: [PATCH 13/14] Clarify endianess --- zkevm-circuits/src/util/word.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zkevm-circuits/src/util/word.rs b/zkevm-circuits/src/util/word.rs index 6b13f1a5c3..029fcd2adb 100644 --- a/zkevm-circuits/src/util/word.rs +++ b/zkevm-circuits/src/util/word.rs @@ -517,7 +517,7 @@ impl From> for Word32Cell { } } -/// Return the hash of the empty code as a Word> +/// Return the hash of the empty code as a Word> in little-endian. pub fn empty_code_hash_word_value() -> Word> { Word::from(CodeDB::empty_code_hash()).into_value() } From 8b8ea051554966e1df0e76650310d07b3d2c0b75 Mon Sep 17 00:00:00 2001 From: Leo Lara Date: Wed, 21 Jun 2023 11:30:43 +0800 Subject: [PATCH 14/14] Better name query_advice --- zkevm-circuits/src/bytecode_circuit/circuit.rs | 14 +++++++++----- zkevm-circuits/src/util/word.rs | 10 +++++++--- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/zkevm-circuits/src/bytecode_circuit/circuit.rs b/zkevm-circuits/src/bytecode_circuit/circuit.rs index 6cad140b4c..5b78de6b74 100644 --- a/zkevm-circuits/src/bytecode_circuit/circuit.rs +++ b/zkevm-circuits/src/bytecode_circuit/circuit.rs @@ -281,7 +281,7 @@ impl SubCircuitConfig for BytecodeCircuitConfig { cb.require_equal_word( "assert cur.hash == EMPTY_HASH", - bytecode_table.code_hash.query(meta, Rotation::cur()), + bytecode_table.code_hash.query_advice(meta, Rotation::cur()), empty_hash_word, ); @@ -322,8 +322,10 @@ impl SubCircuitConfig for BytecodeCircuitConfig { cb.require_equal_word( "next.hash == cur.hash", - bytecode_table.code_hash.query(meta, Rotation::next()), - bytecode_table.code_hash.query(meta, Rotation::cur()), + bytecode_table + .code_hash + .query_advice(meta, Rotation::next()), + bytecode_table.code_hash.query_advice(meta, Rotation::cur()), ); cb.require_equal( @@ -365,8 +367,10 @@ impl SubCircuitConfig for BytecodeCircuitConfig { cb.require_equal_word( "next.hash == cur.hash", - bytecode_table.code_hash.query(meta, Rotation::next()), - bytecode_table.code_hash.query(meta, Rotation::cur()), + bytecode_table + .code_hash + .query_advice(meta, Rotation::next()), + bytecode_table.code_hash.query_advice(meta, Rotation::cur()), ); cb.require_equal( diff --git a/zkevm-circuits/src/util/word.rs b/zkevm-circuits/src/util/word.rs index 029fcd2adb..cca33a8049 100644 --- a/zkevm-circuits/src/util/word.rs +++ b/zkevm-circuits/src/util/word.rs @@ -50,7 +50,7 @@ impl WordLimbs { impl WordLimbs, N> { /// Query advice of WordLibs of columns advice - pub fn query( + pub fn query_advice( &self, meta: &mut VirtualCells, at: Rotation, @@ -393,8 +393,12 @@ impl Word> { impl Word> { /// Query advice of Word of columns advice - pub fn query(&self, meta: &mut VirtualCells, at: Rotation) -> Word> { - self.0.query(meta, at).to_word() + pub fn query_advice( + &self, + meta: &mut VirtualCells, + at: Rotation, + ) -> Word> { + self.0.query_advice(meta, at).to_word() } }