Skip to content
This repository has been archived by the owner on Jul 5, 2024. It is now read-only.

Commit

Permalink
Bytecode Circuit: Refactor word_rlc into word lo/hi (#1468)
Browse files Browse the repository at this point in the history
### Description

Bytecode Circuit: Refactor word_rlc into word lo/hi

### Issue Link

Closes
#1380

### Type of change

- [X] Refactor
- [X] Lo/Hi

### Contents

Bytecode Circuit: Refactor word_rlc into word lo/hi

### Rationale

In Issue

### How Has This Been Tested?

Running unit tests
  • Loading branch information
leolara authored Jun 22, 2023
1 parent cb6c17c commit c4dfebb
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 70 deletions.
104 changes: 48 additions & 56 deletions zkevm-circuits/src/bytecode_circuit/circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,18 @@ use crate::{
evm_circuit::util::{
and,
constraint_builder::{BaseConstraintBuilder, ConstrainBuilderCommon},
not, or, rlc, select,
not, or, select,
},
table::{BytecodeFieldTag, BytecodeTable, KeccakTable, LookupTable},
util::{get_push_size, Challenges, Expr, SubCircuit, SubCircuitConfig},
util::{
get_push_size,
word::{empty_code_hash_word_value, Word, Word32, WordExpr},
Challenges, Expr, SubCircuit, SubCircuitConfig,
},
witness,
};
use bus_mapping::state_db::EMPTY_CODE_HASH_LE;
use eth_types::{Field, ToLittleEndian};
use eth_types::Field;
use gadgets::is_zero::{IsZeroChip, IsZeroInstruction};
use halo2_proofs::{
circuit::{Layouter, Region, Value},
Expand All @@ -31,7 +35,7 @@ use super::{
pub struct BytecodeCircuitRow<F: Field> {
offset: usize,
last_row_offset: usize,
code_hash: Value<F>,
code_hash: Word<Value<F>>,
tag: F,
index: F,
is_code: F,
Expand Down Expand Up @@ -272,15 +276,13 @@ 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_word: Word<Expression<F>> =
Word32::new(*EMPTY_CODE_HASH_LE).to_expr().to_word();

cb.require_equal(
cb.require_equal_word(
"assert cur.hash == EMPTY_HASH",
meta.query_advice(bytecode_table.code_hash, Rotation::cur()),
empty_hash,
bytecode_table.code_hash.query_advice(meta, Rotation::cur()),
empty_hash_word,
);

cb.gate(and::expr(vec![
Expand Down Expand Up @@ -318,10 +320,12 @@ impl<F: Field> SubCircuitConfig<F> for BytecodeCircuitConfig<F> {
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()),
bytecode_table
.code_hash
.query_advice(meta, Rotation::next()),
bytecode_table.code_hash.query_advice(meta, Rotation::cur()),
);

cb.require_equal(
Expand Down Expand Up @@ -361,10 +365,12 @@ impl<F: Field> SubCircuitConfig<F> for BytecodeCircuitConfig<F> {
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()),
bytecode_table
.code_hash
.query_advice(meta, Rotation::next()),
bytecode_table.code_hash.query_advice(meta, Rotation::cur()),
);

cb.require_equal(
Expand Down Expand Up @@ -427,7 +433,7 @@ impl<F: Field> SubCircuitConfig<F> for BytecodeCircuitConfig<F> {
]))
});
meta.lookup_any(
"keccak256_table_lookup(cur.value_rlc, cur.length, cur.hash)",
"keccak256_table_lookup(cur.value_rlc, cur.length, cur.hash_word)",
|meta| {
let enable = and::expr(vec![
meta.query_fixed(q_enable, Rotation::cur()),
Expand Down Expand Up @@ -515,7 +521,7 @@ impl<F: Field> BytecodeCircuitConfig<F> {

// 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`
Expand Down Expand Up @@ -548,20 +554,12 @@ impl<F: Field> BytecodeCircuitConfig<F> {
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),
] {
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(())
},
Expand All @@ -584,11 +582,7 @@ impl<F: Field> BytecodeCircuitConfig<F> {
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::from(bytecode.rows[0].code_hash).into_value();

for (idx, row) in bytecode.rows.iter().enumerate() {
if fail_fast && *offset > last_row_offset {
Expand Down Expand Up @@ -642,7 +636,7 @@ impl<F: Field> BytecodeCircuitConfig<F> {
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)?;
}
}

Expand All @@ -652,20 +646,15 @@ impl<F: Field> BytecodeCircuitConfig<F> {
fn set_padding_row(
&self,
region: &mut Region<'_, F>,
challenges: &Challenges<Value<F>>,
offset: usize,
last_row_offset: usize,
) -> Result<(), Error> {
let empty_hash = challenges
.evm_word()
.map(|challenge| rlc::value(EMPTY_CODE_HASH_LE.as_ref(), challenge));

self.set_row(
region,
BytecodeCircuitRow {
offset,
last_row_offset,
code_hash: empty_hash,
code_hash: empty_code_hash_word_value(),
tag: F::from(BytecodeFieldTag::Header as u64),
value_rlc: Value::known(F::ZERO),
..Default::default()
Expand Down Expand Up @@ -720,17 +709,20 @@ impl<F: Field> BytecodeCircuitConfig<F> {
|| Value::known(value),
)?;
}
for (name, column, value) in [
("code_hash", self.bytecode_table.code_hash, row.code_hash),
("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,
|| format!("assign code_hash {}", offset),
self.bytecode_table.code_hash,
offset,
)?;

self.push_data_left_is_zero.assign(
region,
Expand Down
6 changes: 5 additions & 1 deletion zkevm-circuits/src/table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ use crate::{
copy_circuit::util::number_or_hash_to_word,
evm_circuit::util::rlc,
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,
},
Expand Down
13 changes: 4 additions & 9 deletions zkevm-circuits/src/table/bytecode_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,7 @@ impl_expr!(BytecodeFieldTag);
#[derive(Clone, Debug)]
pub struct BytecodeTable {
/// Code Hash
pub code_hash_word: word::Word<Column<Advice>>,
#[deprecated]
/// Code Hash
pub code_hash: Column<Advice>,
pub code_hash: word::Word<Column<Advice>>,
/// Tag
pub tag: Column<Advice>,
/// Index
Expand All @@ -32,10 +29,8 @@ impl BytecodeTable {
/// Construct a new BytecodeTable
pub fn construct<F: Field>(meta: &mut ConstraintSystem<F>) -> 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 = word::Word::new([meta.advice_column(), meta.advice_column()]);
Self {
code_hash_word,
code_hash,
tag,
index,
Expand Down Expand Up @@ -89,8 +84,8 @@ impl BytecodeTable {
impl<F: Field> LookupTable<F> for BytecodeTable {
fn columns(&self) -> Vec<Column<Any>> {
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(),
Expand Down
5 changes: 3 additions & 2 deletions zkevm-circuits/src/table/keccak_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,12 +134,13 @@ impl KeccakTable {
&self,
value_rlc: Column<Advice>,
length: Column<Advice>,
code_hash: Column<Advice>,
code_hash: Word<Column<Advice>>,
) -> Vec<(Column<Advice>, Column<Advice>)> {
vec![
(value_rlc, self.input_rlc),
(length, self.input_len),
(code_hash, self.output_rlc),
(code_hash.lo(), self.output.lo()),
(code_hash.hi(), self.output.hi()),
]
}
}
40 changes: 38 additions & 2 deletions zkevm-circuits/src/util/word.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
// - 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::CodeDB;
use eth_types::{Field, ToLittleEndian, H160, H256};
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;

Expand Down Expand Up @@ -46,6 +48,24 @@ impl<T, const N: usize> WordLimbs<T, N> {
}
}

impl<const N: usize> WordLimbs<Column<Advice>, N> {
/// Query advice of WordLibs of columns advice
pub fn query_advice<F: Field>(
&self,
meta: &mut VirtualCells<F>,
at: Rotation,
) -> WordLimbs<Expression<F>, N> {
WordLimbs::new(self.limbs.map(|column| meta.query_advice(column, at)))
}
}

impl<const N: usize> WordLimbs<u8, N> {
/// Convert WordLimbs of u8 to WordLimbs of expressions
pub fn to_expr<F: Field>(&self) -> WordLimbs<Expression<F>, N> {
WordLimbs::new(self.limbs.map(|v| Expression::Constant(F::from(v as u64))))
}
}

impl<T: Default, const N: usize> Default for WordLimbs<T, N> {
fn default() -> Self {
Self {
Expand Down Expand Up @@ -363,6 +383,17 @@ impl<F: Field> Word<Value<F>> {
}
}

impl Word<Column<Advice>> {
/// Query advice of Word of columns advice
pub fn query_advice<F: Field>(
&self,
meta: &mut VirtualCells<F>,
at: Rotation,
) -> Word<Expression<F>> {
self.0.query_advice(meta, at).to_word()
}
}

impl<F: Field> WordExpr<F> for Word<Cell<F>> {
fn to_word(&self) -> Word<Expression<F>> {
self.word_expr().to_word()
Expand Down Expand Up @@ -428,7 +459,7 @@ impl<F: Field> WordExpr<F> for Word<Expression<F>> {

impl<F: Field, const N1: usize> WordLimbs<Expression<F>, 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
Expand Down Expand Up @@ -481,4 +512,9 @@ impl<F: Field> From<WordLegacy<F>> for Word32Cell<F> {
}
}

/// Return the hash of the empty code as a Word<Value<F>> in little-endian.
pub fn empty_code_hash_word_value<F: Field>() -> Word<Value<F>> {
Word::from(CodeDB::empty_code_hash()).into_value()
}

// TODO unittest

0 comments on commit c4dfebb

Please sign in to comment.