diff --git a/zkevm-circuits/src/pi_circuit.rs b/zkevm-circuits/src/pi_circuit.rs index fea0ffd29b6..9f5e334d686 100644 --- a/zkevm-circuits/src/pi_circuit.rs +++ b/zkevm-circuits/src/pi_circuit.rs @@ -1,6 +1,6 @@ //! Public Input Circuit implementation -use std::{marker::PhantomData, iter}; +use std::{iter, marker::PhantomData}; use eth_types::{ geth_types::{BlockConstants, Transaction}, @@ -12,14 +12,18 @@ use itertools::Itertools; use keccak256::keccak_arith::Keccak; use crate::{ - table::{BlockTable, LookupTable, TxFieldTag, TxTable, KeccakTable}, + evm_circuit::{ + param::{N_BYTES_BLOCK, N_BYTES_EXTRA_VALUE, N_BYTES_TX, N_BYTES_U64}, + util::{constraint_builder::BaseConstraintBuilder, rlc}, + }, + table::{BlockTable, KeccakTable, LookupTable, TxFieldTag, TxTable}, tx_circuit::TX_LEN, util::{random_linear_combine_word as rlc, Challenges, SubCircuit, SubCircuitConfig}, - witness, evm_circuit::{util::{constraint_builder::BaseConstraintBuilder, rlc}, param::{N_BYTES_U64, N_BYTES_BLOCK, N_BYTES_TX, N_BYTES_EXTRA_VALUE}}, + witness, }; use gadgets::{ is_zero::IsZeroChip, - util::{and, not, or, Expr}, + util::{and, not, or, select, Expr}, }; use halo2_proofs::{ circuit::{AssignedCell, Layouter, Region, Value}, @@ -184,13 +188,18 @@ impl PublicData { let result = iter::empty() .chain(0u8.to_be_bytes()) // zero byte .chain(block_values.coinbase.to_fixed_bytes()) // coinbase - .chain(block_values.gas_limit.to_be_bytes()) //gas_limit + .chain(block_values.gas_limit.to_be_bytes()) // gas_limit .chain(block_values.number.to_be_bytes()) // number .chain(block_values.timestamp.to_be_bytes()) // timestamp .chain(block_values.difficulty.to_le_bytes()) // difficulty .chain(block_values.base_fee.to_le_bytes()) // base_fee .chain(block_values.chain_id.to_be_bytes()) // chain_id - .chain(block_values.history_hashes.iter().flat_map(|prev_hash| prev_hash.to_fixed_bytes())); // history_hashes + .chain( + block_values + .history_hashes + .iter() + .flat_map(|prev_hash| prev_hash.to_fixed_bytes()), + ); // history_hashes // Assign extra fields let extra_vals = self.get_extra_values(); @@ -198,7 +207,6 @@ impl PublicData { .chain(extra_vals.state_root.to_fixed_bytes()) // block state root .chain(extra_vals.prev_state_root.to_fixed_bytes()); // previous block state root - // Assign Tx table let tx_field_byte_fn = |tx_id: u64, tag: TxFieldTag, index: u64, value_bytes: &[u8]| { iter::empty() @@ -209,64 +217,90 @@ impl PublicData { }; let tx_bytes_fn = |tx_id: u64, index: u64, tx: &TxValues| { vec![ - (TxFieldTag::Nonce, tx.nonce.to_le_bytes().to_vec()), // nonce - (TxFieldTag::Gas, tx.gas_limit.to_le_bytes().to_vec()), // gas - (TxFieldTag::GasPrice, tx.gas_price.to_le_bytes().to_vec()), // gas price - (TxFieldTag::CallerAddress, tx.from_addr.as_fixed_bytes().to_vec()), // from_addr - (TxFieldTag::CalleeAddress, tx.to_addr.as_fixed_bytes().to_vec()), // to_addr - (TxFieldTag::IsCreate, tx.is_create.to_be_bytes().to_vec()), // is_create - (TxFieldTag::Value,tx.value.to_le_bytes().to_vec()), // value - (TxFieldTag::CallDataLength, tx.call_data_len.to_be_bytes().to_vec()), // call_data_len - (TxFieldTag::CallDataGasCost, tx.call_data_gas_cost.to_be_bytes().to_vec()), // call_data_gas_cost - (TxFieldTag::TxSignHash, tx.tx_sign_hash.to_vec()), // tx sign hash - ].iter().flat_map( - move |(tag, value_bytes)| { - tx_field_byte_fn(tx_id, *tag, index, value_bytes) - }, - ).collect_vec() + (TxFieldTag::Nonce, tx.nonce.to_le_bytes().to_vec()), // nonce + (TxFieldTag::Gas, tx.gas_limit.to_le_bytes().to_vec()), // gas + (TxFieldTag::GasPrice, tx.gas_price.to_le_bytes().to_vec()), // gas price + ( + TxFieldTag::CallerAddress, + tx.from_addr.as_fixed_bytes().to_vec(), + ), // from_addr + ( + TxFieldTag::CalleeAddress, + tx.to_addr.as_fixed_bytes().to_vec(), + ), // to_addr + (TxFieldTag::IsCreate, tx.is_create.to_be_bytes().to_vec()), // is_create + (TxFieldTag::Value, tx.value.to_le_bytes().to_vec()), // value + ( + TxFieldTag::CallDataLength, + tx.call_data_len.to_be_bytes().to_vec(), + ), // call_data_len + ( + TxFieldTag::CallDataGasCost, + tx.call_data_gas_cost.to_be_bytes().to_vec(), + ), // call_data_gas_cost + (TxFieldTag::TxSignHash, tx.tx_sign_hash.to_vec()), // tx sign hash + ] + .iter() + .flat_map(move |(tag, value_bytes)| tx_field_byte_fn(tx_id, *tag, index, value_bytes)) + .collect_vec() }; let txs_values = self.get_tx_table_values(); - let tx_values_default= TxValues::default(); + let tx_values_default = TxValues::default(); // all tx bytes including tx padding - let all_tx_bytes = iter::empty().chain( - &txs_values - ).chain( - (0..(max_txs - txs_values.len())).into_iter().map(|_| &tx_values_default) - ).enumerate() - .flat_map(|(i, tx)| { - let i:u64 = i.try_into().unwrap(); - tx_bytes_fn(i+1, 0, tx) - }); - + let all_tx_bytes = iter::empty() + .chain(&txs_values) + .chain( + (0..(max_txs - txs_values.len())) + .into_iter() + .map(|_| &tx_values_default), + ) + .enumerate() + .flat_map(|(i, tx)| { + let i: u64 = i.try_into().unwrap(); + tx_bytes_fn(i + 1, 0, tx) + }); + // first empty row happened here let result = result - .chain(tx_field_byte_fn(0, TxFieldTag::Null, 0, &[0u8; 1])) // empty row + .chain(tx_field_byte_fn(0, TxFieldTag::Null, 0, &[0u8; 1])) // empty row .chain(all_tx_bytes); - + // Tx Table CallData let txs = self.txs(); - let all_calldata = txs.iter().enumerate().flat_map(|(i, tx)| { - tx.call_data.0.iter().enumerate().map(move |(index, byte)| (i, index, [*byte; 1])) - }).collect_vec(); + let all_calldata = txs + .iter() + .enumerate() + .flat_map(|(i, tx)| { + tx.call_data + .0 + .iter() + .enumerate() + .map(move |(index, byte)| (i, index, [*byte; 1])) + }) + .collect_vec(); let calldata_count = all_calldata.len(); // concat call data with call data padding let calldata_chain = iter::empty() .chain(all_calldata) .chain( - (0..max_calldata-calldata_count).into_iter().map(|_| (0usize, 0usize, [0u8; 1])) + (0..max_calldata - calldata_count) + .into_iter() + .map(|_| (0usize, 0usize, [0u8; 1])), ) - .flat_map( - |(i, index, byte)| { - let i:u64 = i.try_into().unwrap(); - tx_field_byte_fn(i + 1, TxFieldTag::CallData, index.try_into().unwrap(), byte.as_ref()) - } - ); + .flat_map(|(i, index, byte)| { + let i: u64 = i.try_into().unwrap(); + tx_field_byte_fn( + i + 1, + TxFieldTag::CallData, + index.try_into().unwrap(), + byte.as_ref(), + ) + }); result.chain(calldata_chain).collect_vec() - } // generate public data from validator perspective fn get_pi_digest(&self, max_txs: usize, max_calldata: usize) -> H256 { @@ -275,7 +309,6 @@ impl PublicData { let digest = keccak.digest(); H256(digest.try_into().unwrap()) // assume digest convert always success } - } /// Config for PiCircuit @@ -296,7 +329,8 @@ pub struct PiCircuitConfig { // The value can be one byte or multiple bytes. The order of values is pre-defined and // hardcode. can't use selector here because we need rotation q_rpi_value_start: Column, - // q_digest_field_start: mark starting of hi and low. can't use selector here because we need rotation + // q_digest_field_start: mark starting of hi and low. can't use selector here because we need + // rotation q_digest_value_start: Column, tx_id_inv: Column, @@ -305,6 +339,7 @@ pub struct PiCircuitConfig { fixed_u16: Column, calldata_gas_cost: Column, is_final: Column, + is_value_rlc: Column, // raw_public_inputs: Column, // rpi_rlc_acc: Column, @@ -317,19 +352,19 @@ pub struct PiCircuitConfig { // rpi_bytes_length_acc: accumulate the rpi_bytes byte length for keccak lookup. rpi_bytes_length_acc: Column, // rpi_value_rlc: This is similar with rpi_bytes_keccakrlc, while the key differences is - // it's rlc in value based and reset for next new value. Besides it also evm word challenge - rpi_value_rlc:Column, + // it's rlc in value based and reset for next new value. rand value is control by is_value_rlc + rpi_value_rlc: Column, // rpi_digest_bytes: Keccak digest raw bytes laid verticlly in this column - rpi_digest_bytes: Column, + rpi_digest_bytes: Column, // rpi_digest_bytes_rlc: rlc of raw digest byte. This is for Keccak // output rlc - rpi_digest_bytes_rlc: Column, + rpi_digest_bytes_rlc: Column, // rpi_digest_bytes_lc: this is just the `lc` linear combination with r=BYTE_POW_BASE. - rpi_digest_bytes_lc: Column, + rpi_digest_bytes_lc: Column, q_rpi_byte_not_end: Selector, q_digest_byte_not_end: Selector, - + pi_instance: Column, // keccak_digest_hi, keccak_digest_lo _marker: PhantomData, @@ -370,7 +405,6 @@ impl SubCircuitConfig for PiCircuitConfig { challenges, }: Self::ConfigArgs, ) -> Self { - let q_tx_table = meta.complex_selector(); let q_tx_calldata = meta.complex_selector(); let q_calldata_start = meta.complex_selector(); @@ -391,26 +425,17 @@ impl SubCircuitConfig for PiCircuitConfig { let calldata_gas_cost = meta.advice_column_in(SecondPhase); let is_final = meta.advice_column(); - // refer https://github.com/privacy-scaling-explorations/zkevm-specs/blob/master/src/zkevm_specs/pi_circuit.py#L467 - // for raw_public_inputs column layout - // let raw_public_inputs = meta.advice_column_in(SecondPhase); - // let rpi_rlc_acc = meta.advice_column_in(SecondPhase); - // let rand_rpi = meta.advice_column(); let q_start = meta.selector(); let q_rpi_byte_not_end = meta.complex_selector(); let q_digest_byte_not_end = meta.complex_selector(); - // q_rpi_value_start: assure rpi_bytes sync with rpi_value_rlc when cross boundary. - // because we layout rpi bytes vertically, which is concated from multiple original values. - // The value can be one byte or multiple bytes. The order of values is pre-defined and - // hardcode. can't use selector here because we need rotation let q_rpi_value_start = meta.fixed_column(); - // q_digest_field_start: mark starting of hi and low. can't use selector here because we need rotation let q_digest_value_start = meta.fixed_column(); let rpi_bytes = meta.advice_column(); let rpi_bytes_keccakrlc = meta.advice_column_in(SecondPhase); let rpi_bytes_length_acc = meta.advice_column(); let rpi_value_rlc = meta.advice_column_in(SecondPhase); + let is_value_rlc = meta.fixed_column(); let rpi_digest_bytes = meta.advice_column(); let rpi_digest_bytes_rlc = meta.advice_column_in(SecondPhase); let rpi_digest_bytes_lc = meta.advice_column(); @@ -429,7 +454,7 @@ impl SubCircuitConfig for PiCircuitConfig { meta.enable_equality(rpi_value_rlc); meta.enable_equality(rpi_bytes_keccakrlc); meta.enable_equality(rpi_bytes_length_acc); - + meta.enable_equality(rpi_digest_bytes_rlc); meta.enable_equality(rpi_digest_bytes_lc); @@ -440,26 +465,23 @@ impl SubCircuitConfig for PiCircuitConfig { // 1: rpi_bytes_keccakrlc[0] = rpi_bytes[0] // rpi_bytes_length_acc[0] = 1 - meta.create_gate( - "rpi_bytes_keccakrlc[0] = rpi_bytes[0]", - |meta| { - let mut cb = BaseConstraintBuilder::default(); - - cb.require_equal( - "rpi_bytes_keccakrlc[0] = rpi_bytes[0]", - meta.query_advice(rpi_bytes_keccakrlc, Rotation::cur()), - meta.query_advice(rpi_bytes, Rotation::cur()), - ); + meta.create_gate("rpi_bytes_keccakrlc[0] = rpi_bytes[0]", |meta| { + let mut cb = BaseConstraintBuilder::default(); - cb.require_equal( - "rpi_bytes_length_acc[0] = 1", - meta.query_advice(rpi_bytes_length_acc, Rotation::cur()), - 1.expr(), - ); + cb.require_equal( + "rpi_bytes_keccakrlc[0] = rpi_bytes[0]", + meta.query_advice(rpi_bytes_keccakrlc, Rotation::cur()), + meta.query_advice(rpi_bytes, Rotation::cur()), + ); - cb.gate(meta.query_selector(q_start)) - }, - ); + cb.require_equal( + "rpi_bytes_length_acc[0] = 1", + meta.query_advice(rpi_bytes_length_acc, Rotation::cur()), + 1.expr(), + ); + + cb.gate(meta.query_selector(q_start)) + }); // 2: rpi_bytes_keccakrlc[i+1] = keccak_rand * rpi_bytes_keccakrlc[i] + rpi_bytes[i+1]" // rpi_bytes_length_acc[i+1] = rpi_bytes_length_acc[i] @@ -477,12 +499,12 @@ impl SubCircuitConfig for PiCircuitConfig { let rpi_bytes_length_acc_next = meta.query_advice(rpi_bytes_length_acc, Rotation::next()); let keccak_rand = challenges.keccak_input(); cb.require_equal( - "rpi_bytes_keccakrlc[i+1] = keccak_rand * rpi_bytes_keccakrlc[i] + rpi_bytes[i+1]", rpi_bytes_keccakrlc_next, + "rpi_bytes_keccakrlc[i+1] = keccak_rand * rpi_bytes_keccakrlc[i] + rpi_bytes[i+1]", rpi_bytes_keccakrlc_next, rpi_bytes_keccakrlc_cur*keccak_rand + rpi_bytes_next, ); cb.require_equal( - "rpi_bytes_length_acc[i+1] = rpi_bytes_length_acc[i] + 1", rpi_bytes_length_acc_next, + "rpi_bytes_length_acc[i+1] = rpi_bytes_length_acc[i] + 1", rpi_bytes_length_acc_next, rpi_bytes_length_acc_cur + 1.expr(), ); @@ -490,32 +512,36 @@ impl SubCircuitConfig for PiCircuitConfig { }, ); - // 3: q_rpi_value_start is bool && q_digest_value_start is bool && q_rpi_keccak_lookup is bool - meta.create_gate("q_rpi_value_start is bool", |meta| { + // 3: q_rpi_value_start is bool && q_digest_value_start is bool && q_rpi_keccak_lookup is + // bool + meta.create_gate("fixed column is bool", |meta| { let q_rpi_value_start_cur = meta.query_fixed(q_rpi_value_start, Rotation::cur()); let q_digest_value_start_cur = meta.query_fixed(q_digest_value_start, Rotation::cur()); - + let is_value_rlc_cur = meta.query_fixed(is_value_rlc, Rotation::cur()); + vec![or::expr([ q_rpi_value_start_cur.clone() * (1.expr() - q_rpi_value_start_cur), q_digest_value_start_cur.clone() * (1.expr() - q_digest_value_start_cur), + is_value_rlc_cur.clone() * (1.expr() - is_value_rlc_cur), ])] }); - // 4: rpi_value_rlc[i+1] = rpi_value_rlc[i]* r + rpi_bytes[i+1] if q_rpi_value_start[i+1] != - // 1 + // 4: rpi_value_rlc[i+1] = rpi_value_rlc[i] * (is_value_rlc[i] ? evm_rand : byte_pow_base ) + // + rpi_bytes[i+1] meta.create_gate( - "rpi_value_rlc[i+1] = rpi_value_rlc[i]* r + rpi_bytes[i+1] if q_rpi_value_start[i+1] != 1", + "rpi_value_rlc[i+1] = rpi_value_rlc[i] * (is_value_rlc[i] ? evm_rand : byte_pow_base) + rpi_bytes[i+1]", |meta| { let mut cb = BaseConstraintBuilder::default(); let q_rpi_value_start_next = meta.query_fixed(q_rpi_value_start, Rotation::next()); + let is_value_rlc_cur = meta.query_fixed(is_value_rlc, Rotation::next()); let rpi_value_rlc_next = meta.query_advice(rpi_value_rlc, Rotation::next()); let rpi_value_rlc_cur = meta.query_advice(rpi_value_rlc, Rotation::cur()); let rpi_bytes_next = meta.query_advice(rpi_bytes, Rotation::next()); - let r = challenges.evm_word(); + let r = select::expr(is_value_rlc_cur, challenges.evm_word(), BYTE_POW_BASE.expr()); cb.require_equal( "rpi_value_rlc[i+1] = rpi_value_rlc[i]* r + rpi_bytes[i+1]", - rpi_value_rlc_next, + rpi_value_rlc_next, rpi_value_rlc_cur * r + rpi_bytes_next, ); @@ -557,7 +583,7 @@ impl SubCircuitConfig for PiCircuitConfig { let r = challenges.evm_word(); cb.require_equal( - "rpi_digest_bytes_rlc[i+1] = rpi_digest_bytes_rlc[i] * r + rpi_digest_bytes[i+1]", + "rpi_digest_bytes_rlc[i+1] = rpi_digest_bytes_rlc[i] * r + rpi_digest_bytes[i+1]", rpi_digest_bytes_rlc_next, rpi_digest_bytes_rlc_cur * r + rpi_digest_bytes_next ); @@ -573,31 +599,36 @@ impl SubCircuitConfig for PiCircuitConfig { let rpi_digest_bytes_lc_cur = meta.query_advice(rpi_digest_bytes_lc, Rotation::cur()); let rpi_digest_bytes_cur = meta.query_advice(rpi_digest_bytes, Rotation::cur()); - cb.require_equal("rpi_digest_bytes_lc[0] = rpi_digest_bytes[0]", rpi_digest_bytes_lc_cur, rpi_digest_bytes_cur); - + cb.require_equal( + "rpi_digest_bytes_lc[0] = rpi_digest_bytes[0]", + rpi_digest_bytes_lc_cur, + rpi_digest_bytes_cur, + ); + cb.gate(meta.query_selector(q_start)) }); - // 9. rpi_digest_bytes_lc[i+1] = rpi_digest_bytes_lc[i] * BYTE_POW_BASE + rpi_digest_bytes[i+1] if - // q_digest_value_start[i+1] != 1 && q_digest_byte_not_end[i] == 1 + // 9. rpi_digest_bytes_lc[i+1] = rpi_digest_bytes_lc[i] * BYTE_POW_BASE + + // rpi_digest_bytes[i+1] if q_digest_value_start[i+1] != 1 && + // q_digest_byte_not_end[i] == 1 meta.create_gate( " rpi_digest_bytes_lc[i+1] = rpi_digest_bytes_lc[i] * BYTE_POW_BASE + rpi_digest_bytes[i+1] if // q_digest_value_start[i+1] != 1 && q_digest_byte_not_end[i] == 1", |meta| { let mut cb = BaseConstraintBuilder::default(); - + let q_digest_byte_not_end_cur = meta.query_selector(q_digest_byte_not_end); let q_digest_value_start_next = meta.query_fixed(q_digest_value_start, Rotation::next()); let rpi_digest_bytes_lc_next = meta.query_advice(rpi_digest_bytes_lc, Rotation::next()); let rpi_digest_bytes_lc_cur = meta.query_advice(rpi_digest_bytes_lc, Rotation::cur()); let rpi_digest_bytes_next = meta.query_advice(rpi_digest_bytes, Rotation::next()); - + cb.require_equal( - "rpi_digest_bytes_lc[i+1] = rpi_digest_bytes_lc[i] * BYTE_POW_BASE + rpi_digest_bytes[i+1]", - rpi_digest_bytes_lc_next, + "rpi_digest_bytes_lc[i+1] = rpi_digest_bytes_lc[i] * BYTE_POW_BASE + rpi_digest_bytes[i+1]", + rpi_digest_bytes_lc_next, rpi_digest_bytes_lc_cur * BYTE_POW_BASE.expr() + rpi_digest_bytes_next ); - + cb.gate(and::expr([not::expr(q_digest_value_start_next), q_digest_byte_not_end_cur])) }, ); @@ -609,39 +640,57 @@ impl SubCircuitConfig for PiCircuitConfig { |meta| { let mut cb = BaseConstraintBuilder::default(); - let q_digest_value_start_cur = meta.query_fixed(q_digest_value_start, Rotation::cur()); - let rpi_digest_bytes_lc_cur = meta.query_advice(rpi_digest_bytes_lc, Rotation::cur()); + let q_digest_value_start_cur = + meta.query_fixed(q_digest_value_start, Rotation::cur()); + let rpi_digest_bytes_lc_cur = + meta.query_advice(rpi_digest_bytes_lc, Rotation::cur()); let rpi_digest_bytes_cur = meta.query_advice(rpi_digest_bytes, Rotation::cur()); - cb.require_equal("rpi_digest_bytes_lc[i] = rpi_digest_bytes[i]", rpi_digest_bytes_cur, rpi_digest_bytes_lc_cur); + cb.require_equal( + "rpi_digest_bytes_lc[i] = rpi_digest_bytes[i]", + rpi_digest_bytes_cur, + rpi_digest_bytes_lc_cur, + ); cb.gate(q_digest_value_start_cur) }, ); - // 11. lookup rpi_bytes_keccakrlc against rpi_digest_bytes_rlc - meta.lookup_any("lookup rpi_bytes_keccakrlc against rpi_digest_bytes_rlc", |meta| { - let is_enabled = meta.query_advice(keccak_table.is_enabled, Rotation::cur()); - let input_rlc = meta.query_advice(keccak_table.input_rlc, Rotation::cur()); - let input_len = meta.query_advice(keccak_table.input_len, Rotation::cur()); - let output_rlc = meta.query_advice(keccak_table.output_rlc, Rotation::cur()); - - // is_enabled - let q_rpi_keccak_lookup = meta.query_selector(q_rpi_keccak_lookup); - // input_rlc - let rpi_bytes_keccakrlc_cur = meta.query_advice(rpi_bytes_keccakrlc, Rotation::cur()); - // output_rlc - let rpi_digest_bytes_rlc_cur = meta.query_advice(rpi_digest_bytes_rlc, Rotation::cur()); - // length - let rpi_bytes_length_acc_cur = meta.query_advice(rpi_bytes_length_acc, Rotation::cur()); - - vec![ - (q_rpi_keccak_lookup.expr() * 1.expr(), is_enabled), - (q_rpi_keccak_lookup.expr() * rpi_bytes_keccakrlc_cur, input_rlc), - (q_rpi_keccak_lookup.expr() * rpi_bytes_length_acc_cur, input_len), - (q_rpi_keccak_lookup * rpi_digest_bytes_rlc_cur, output_rlc), - ] - }); + // 11. lookup rpi_bytes_keccakrlc against rpi_digest_bytes_rlc + meta.lookup_any( + "lookup rpi_bytes_keccakrlc against rpi_digest_bytes_rlc", + |meta| { + let is_enabled = meta.query_advice(keccak_table.is_enabled, Rotation::cur()); + let input_rlc = meta.query_advice(keccak_table.input_rlc, Rotation::cur()); + let input_len = meta.query_advice(keccak_table.input_len, Rotation::cur()); + let output_rlc = meta.query_advice(keccak_table.output_rlc, Rotation::cur()); + + // is_enabled + let q_rpi_keccak_lookup = meta.query_selector(q_rpi_keccak_lookup); + // input_rlc + let rpi_bytes_keccakrlc_cur = + meta.query_advice(rpi_bytes_keccakrlc, Rotation::cur()); + // output_rlc + let rpi_digest_bytes_rlc_cur = + meta.query_advice(rpi_digest_bytes_rlc, Rotation::cur()); + // length + let rpi_bytes_length_acc_cur = + meta.query_advice(rpi_bytes_length_acc, Rotation::cur()); + + vec![ + (q_rpi_keccak_lookup.expr() * 1.expr(), is_enabled), + ( + q_rpi_keccak_lookup.expr() * rpi_bytes_keccakrlc_cur, + input_rlc, + ), + ( + q_rpi_keccak_lookup.expr() * rpi_bytes_length_acc_cur, + input_len, + ), + (q_rpi_keccak_lookup * rpi_digest_bytes_rlc_cur, output_rlc), + ] + }, + ); let tx_id_is_zero_config = IsZeroChip::configure( meta, @@ -841,6 +890,7 @@ impl SubCircuitConfig for PiCircuitConfig { rpi_bytes_keccakrlc, rpi_bytes_length_acc, rpi_value_rlc, + is_value_rlc, rpi_digest_bytes, rpi_digest_bytes_rlc, rpi_digest_bytes_lc, @@ -862,12 +912,14 @@ impl PiCircuitConfig { /// Return the number of rows for txs and calldata #[inline] fn circuit_len_by_txs_calldata(txs: usize, calldata: usize) -> usize { - N_BYTES_ZERO - + N_BYTES_BLOCK - + N_BYTES_EXTRA_VALUE - + Self::circuit_len_tx_id(txs) + Self::circuit_len_tx_index(txs) + Self::circuit_len_tx_values(txs) - + calldata - + 1 // for keccak lookup + N_BYTES_ZERO + + N_BYTES_BLOCK + + N_BYTES_EXTRA_VALUE + + Self::circuit_len_tx_id(txs) + + Self::circuit_len_tx_index(txs) + + Self::circuit_len_tx_values(txs) + + calldata + + 1 // for keccak lookup } #[inline] @@ -877,19 +929,17 @@ impl PiCircuitConfig { #[inline] fn circuit_len_tx_id(txs: usize) -> usize { - N_BYTES_U64 * TX_LEN * txs - + N_BYTES_U64 // empty row + N_BYTES_U64 * TX_LEN * txs + N_BYTES_U64 // empty row } #[inline] fn circuit_len_tx_index(txs: usize) -> usize { - N_BYTES_U64 * TX_LEN * txs - + N_BYTES_U64 // empty row + N_BYTES_U64 * TX_LEN * txs + N_BYTES_U64 // empty row } fn assign_empty_txtable_row( - &self, - region: &mut Region<'_, F>, + &self, + region: &mut Region<'_, F>, offset: usize, ) -> Result<(), Error> { println!("assign_empty_txtable_row offset {:?}", offset); @@ -944,11 +994,7 @@ impl PiCircuitConfig { Ok(()) } - fn assign_empty_row( - &self, region: - &mut Region<'_, F>, - offset: usize, - ) -> Result<(), Error> { + fn assign_empty_row(&self, region: &mut Region<'_, F>, offset: usize) -> Result<(), Error> { // assign rpi bytes region.assign_advice( || "rpi_bytes", @@ -1005,12 +1051,11 @@ impl PiCircuitConfig { } else { F::zero() }; - // restore tx_value_bytes to Value. Here check bytes length to inpsct whether it can be fit into F. Otherwise rlc it - let tx_value = if tx_value_bytes.len() * 8 > F::CAPACITY as usize { - challenges.evm_word().zip(Value::known(tx_value_bytes)).map(|(r, bytes)| rlc::value(bytes, r)) - } else { - Value::known(F::from(BYTE_POW_BASE)).zip(Value::known(tx_value_bytes)).map(|(r, bytes)| rlc::value(bytes, r)) - }; + let tx_value = challenges + .evm_word() + .zip(Value::known(tx_value_bytes)) + .map(|(r, bytes)| rlc::value(bytes, r)); + let tx_value_inv = tx_value.map(|t| t.invert().unwrap_or(F::zero())); let mut tx_table_cells = vec![]; @@ -1019,71 +1064,75 @@ impl PiCircuitConfig { self.q_tx_table.enable(region, offset)?; // Assign vals to Tx_table - tx_table_cells.push( - region.assign_advice( - || "tx_id", - self.tx_table.tx_id, - offset, - || Value::known(F::from(tx_id as u64)), - )? - ); - region.assign_fixed(|| "tag", self.tx_table.tag, offset, || Value::known(F::from(tag as u64)))?; - - tx_table_cells.push( - region.assign_advice( - || "index", - self.tx_table.index, - offset, - || Value::known(F::from(index as u64)), - )? - ); - tx_table_cells.push( - region.assign_advice( - || "tx_value", - self.tx_table.value, - offset, - || tx_value, - )? - ); + println!("tx_id {:?}", tx_value); + tx_table_cells.push(region.assign_advice( + || "tx_id", + self.tx_table.tx_id, + offset, + || Value::known(F::from(tx_id as u64)), + )?); + region.assign_fixed( + || "tag", + self.tx_table.tag, + offset, + || Value::known(F::from(tag as u64)), + )?; + + tx_table_cells.push(region.assign_advice( + || "index", + self.tx_table.index, + offset, + || Value::known(F::from(index as u64)), + )?); + println!("tx_value {:?}", tx_value); + tx_table_cells.push(region.assign_advice( + || "tx_value", + self.tx_table.value, + offset, + || tx_value, + )?); // tx_id let (_, rpi_value_rlc_cell, _) = self.assign_raw_bytes( - region, - &tx_id.to_be_bytes(), - rpi_bytes_keccakrlc, + region, + &tx_id.to_be_bytes(), + rpi_bytes_keccakrlc, rpi_bytes, - rpi_bytes_length_acc, - challenges, + rpi_bytes_length_acc, + challenges, )?; + println!("tx_id {:?}", rpi_value_rlc_cell); rpi_value_rlc_cells.push(rpi_value_rlc_cell); // index let (_, rpi_value_rlc_cell, _) = self.assign_raw_bytes( - region, - &index.to_be_bytes(), - rpi_bytes_keccakrlc, + region, + &index.to_be_bytes(), + rpi_bytes_keccakrlc, rpi_bytes, - rpi_bytes_length_acc, - challenges, + rpi_bytes_length_acc, + challenges, )?; rpi_value_rlc_cells.push(rpi_value_rlc_cell); // tx value let (_, rpi_value_rlc_cell, _) = self.assign_raw_bytes( - region, - tx_value_bytes, - rpi_bytes_keccakrlc, + region, + tx_value_bytes, + rpi_bytes_keccakrlc, rpi_bytes, - rpi_bytes_length_acc, - challenges, + rpi_bytes_length_acc, + challenges, )?; + println!("tx_value {:?}", rpi_value_rlc_cell); rpi_value_rlc_cells.push(rpi_value_rlc_cell); assert!(rpi_value_rlc_cells.len() == tx_table_cells.len()); - rpi_value_rlc_cells.iter().zip(tx_table_cells).try_for_each(|(left, right)| { - region.constrain_equal(left.cell(), right.cell()) - })?; + rpi_value_rlc_cells + .iter() + .zip(tx_table_cells) + .try_for_each(|(left, right)| region.constrain_equal(left.cell(), right.cell()))?; // derived inverse not belong to TxTable so do not need copy constraints region.assign_advice( @@ -1093,10 +1142,10 @@ impl PiCircuitConfig { || Value::known(tx_id_inv), )?; region.assign_advice( - || "tx_value_inverse", - self.tx_value_inv, - offset, - || tx_value_inv, + || "tx_value_inverse", + self.tx_value_inv, + offset, + || tx_value_inv, )?; Ok(()) @@ -1119,7 +1168,6 @@ impl PiCircuitConfig { is_final: bool, gas_cost: F, ) -> Result<(AssignedCell, AssignedCell), Error> { - println!("assign_tx_calldata_row offset {:?}", offset); let tx_id = F::from(tx_id as u64); let tx_id_inv = tx_id.invert().unwrap_or(F::zero()); @@ -1129,10 +1177,11 @@ impl PiCircuitConfig { let index = F::from(index as u64); // assure calldata can fit into the field. - assert!(tx_value_bytes.len() * 8 <= F::CAPACITY as usize); - - // restore tx_value_bytes to Value. Here check bytes length to inpsct whether it can be fit into F. Otherwise rlc it - let tx_value = Value::known(F::from(BYTE_POW_BASE)).zip(Value::known(tx_value_bytes)).map(|(r, bytes)| rlc::value(bytes, r)); + assert!(tx_value_bytes.len() == 1); + + let tx_value = Value::known(F::from(BYTE_POW_BASE)) + .zip(Value::known(tx_value_bytes)) + .map(|(r, bytes)| rlc::value(bytes, r)); let tx_value_inv = tx_value.map(|v| v.invert().unwrap_or(F::zero())); let is_final = if is_final { F::one() } else { F::zero() }; @@ -1151,12 +1200,7 @@ impl PiCircuitConfig { offset, || Value::known(tx_id_inv), )?; - region.assign_fixed( - || "tag", - self.tx_table.tag, - offset, - || Value::known(tag), - )?; + region.assign_fixed(|| "tag", self.tx_table.tag, offset, || Value::known(tag))?; region.assign_advice( || "index", self.tx_table.index, @@ -1165,12 +1209,9 @@ impl PiCircuitConfig { )?; // constraint it to be equal to tx_table - let tx_value_cell = region.assign_advice( - || "tx_value", - self.tx_table.value, - offset, - || tx_value, - )?; + println!("tx_value offset {:?}", offset); + let tx_value_cell = + region.assign_advice(|| "tx_value", self.tx_table.value, offset, || tx_value)?; region.assign_advice( || "tx_value_inv", @@ -1198,14 +1239,16 @@ impl PiCircuitConfig { )?; // calldata value also need to be in copy constraint - let (rpi_bytes_keccakrlc_cell, rpi_value_rlc_cell, rpi_bytes_length_acc_cell) = self.assign_raw_bytes( - region, - tx_value_bytes, - rpi_bytes_keccakrlc, - rpi_bytes, - rpi_bytes_length_acc, - challenges, - )?; + println!("tx_value rpi_bytes_length_acc {:?}", rpi_bytes_length_acc); + let (rpi_bytes_keccakrlc_cell, rpi_value_rlc_cell, rpi_bytes_length_acc_cell) = self + .assign_raw_bytes( + region, + tx_value_bytes, + rpi_bytes_keccakrlc, + rpi_bytes, + rpi_bytes_length_acc, + challenges, + )?; region.constrain_equal(rpi_value_rlc_cell.cell(), tx_value_cell.cell())?; @@ -1221,16 +1264,16 @@ impl PiCircuitConfig { rpi_bytes: &mut [u8], rpi_bytes_length_acc: &mut usize, challenges: &Challenges>, - ) -> Result<( - AssignedCell, - AssignedCell, - AssignedCell, - ), Error>{ - + ) -> Result<(AssignedCell, AssignedCell, AssignedCell), Error> { assert!(value_bytes.len() > 0); let evm_rand = challenges.evm_word(); let keccak_rand = challenges.keccak_input(); + let mut is_value_rlc: bool = false; + + if value_bytes.len() * 8 > F::CAPACITY as usize { + is_value_rlc = true; + } // assign q_rpi_value_start at the begining of each field region.assign_fixed( @@ -1240,7 +1283,7 @@ impl PiCircuitConfig { || Value::known(F::one()), )?; - let mut cells:Vec> = vec![]; + let mut cells: Vec> = vec![]; value_bytes.iter().enumerate().try_fold( Value::known(F::zero()), @@ -1248,14 +1291,27 @@ impl PiCircuitConfig { rpi_bytes[*rpi_bytes_length_acc - 1] = *byte; // this is mutable for accumulated across value - *rpi_bytes_keccakrlc = rpi_bytes_keccakrlc.zip(keccak_rand) + *rpi_bytes_keccakrlc = rpi_bytes_keccakrlc + .zip(keccak_rand) .and_then(|(acc, rand)| Value::known(acc * rand + F::from(*byte as u64))); - + + // assign is_value_rlc + region.assign_fixed( + || "is_value_rlc", + self.is_value_rlc, + *rpi_bytes_length_acc, + || Value::known(if is_value_rlc { F::one() } else { F::zero() }), + )?; + // this is for local accumulative let rpi_value_rlc = rpi_value_rlc - .zip(evm_rand) + .zip(if is_value_rlc { + evm_rand + } else { + Value::known(F::from(BYTE_POW_BASE)) + }) .and_then(|(acc, rand)| Value::known(acc * rand + F::from(*byte as u64))); - + // assign rpi bytes region.assign_advice( || "rpi_bytes", @@ -1279,7 +1335,7 @@ impl PiCircuitConfig { *rpi_bytes_length_acc, || rpi_value_rlc, )?; - + // assign rpi bytes length acc let rpi_bytes_length_acc_cell = region.assign_advice( || "rpi_bytes_length_acc", @@ -1289,12 +1345,13 @@ impl PiCircuitConfig { )?; // enable q_rpi_byte_not_end - self.q_rpi_byte_not_end.enable(region, *rpi_bytes_length_acc)?; + self.q_rpi_byte_not_end + .enable(region, *rpi_bytes_length_acc)?; - if i == value_bytes.len() -1 { + if i == value_bytes.len() - 1 { cells.push(rpi_bytes_keccakrlc_cell); cells.push(rpi_value_rlc_cell); - cells.push(rpi_bytes_length_acc_cell) + cells.push(rpi_bytes_length_acc_cell); } *rpi_bytes_length_acc += 1; @@ -1304,7 +1361,6 @@ impl PiCircuitConfig { )?; Ok((cells[0].clone(), cells[1].clone(), cells[2].clone())) - } /// Assigns the values for block table in the block_table column @@ -1330,12 +1386,12 @@ impl PiCircuitConfig { || Value::known(F::zero()), )?; let (_, rpi_value_rlc_cell, _) = self.assign_raw_bytes( - region, - &0u8.to_be_bytes(), - rpi_bytes_keccakrlc, + region, + &0u8.to_be_bytes(), + rpi_bytes_keccakrlc, rpi_bytes, - rpi_bytes_length_acc, - challenges, + rpi_bytes_length_acc, + challenges, )?; block_copy_cells.push((block_cell, rpi_value_rlc_cell)); block_table_offset += 1; @@ -1348,12 +1404,12 @@ impl PiCircuitConfig { || Value::known(block_values.coinbase.to_scalar().unwrap()), )?; let (_, rpi_value_rlc_cell, _) = self.assign_raw_bytes( - region, - &block_values.coinbase.to_fixed_bytes(), - rpi_bytes_keccakrlc, + region, + &block_values.coinbase.to_fixed_bytes(), + rpi_bytes_keccakrlc, rpi_bytes, - rpi_bytes_length_acc, - challenges, + rpi_bytes_length_acc, + challenges, )?; block_copy_cells.push((block_cell, rpi_value_rlc_cell)); block_table_offset += 1; @@ -1366,12 +1422,12 @@ impl PiCircuitConfig { || Value::known(F::from(block_values.gas_limit)), )?; let (_, rpi_value_rlc_cell, _) = self.assign_raw_bytes( - region, - &block_values.gas_limit.to_be_bytes(), - rpi_bytes_keccakrlc, + region, + &block_values.gas_limit.to_be_bytes(), + rpi_bytes_keccakrlc, rpi_bytes, - rpi_bytes_length_acc, - challenges, + rpi_bytes_length_acc, + challenges, )?; block_copy_cells.push((block_cell, rpi_value_rlc_cell)); block_table_offset += 1; @@ -1384,12 +1440,12 @@ impl PiCircuitConfig { || Value::known(F::from(block_values.number)), )?; let (_, rpi_value_rlc_cell, _) = self.assign_raw_bytes( - region, - &block_values.number.to_be_bytes(), - rpi_bytes_keccakrlc, + region, + &block_values.number.to_be_bytes(), + rpi_bytes_keccakrlc, rpi_bytes, - rpi_bytes_length_acc, - challenges, + rpi_bytes_length_acc, + challenges, )?; block_copy_cells.push((block_cell, rpi_value_rlc_cell)); block_table_offset += 1; @@ -1402,20 +1458,21 @@ impl PiCircuitConfig { || Value::known(F::from(block_values.timestamp)), )?; let (_, rpi_value_rlc_cell, _) = self.assign_raw_bytes( - region, - &block_values.timestamp.to_be_bytes(), - rpi_bytes_keccakrlc, + region, + &block_values.timestamp.to_be_bytes(), + rpi_bytes_keccakrlc, rpi_bytes, - rpi_bytes_length_acc, - challenges, + rpi_bytes_length_acc, + challenges, )?; block_copy_cells.push((block_cell, rpi_value_rlc_cell)); block_table_offset += 1; // difficulty - let difficulty = challenges.evm_word().zip( - Value::known(block_values.difficulty.to_le_bytes()) - ).map(|(r, bytes)| rlc(bytes, r)); + let difficulty = challenges + .evm_word() + .zip(Value::known(block_values.difficulty.to_le_bytes())) + .map(|(r, bytes)| rlc(bytes, r)); let block_cell = region.assign_advice( || "difficulty", self.block_table.value, @@ -1423,20 +1480,21 @@ impl PiCircuitConfig { || difficulty, )?; let (_, rpi_value_rlc_cell, _) = self.assign_raw_bytes( - region, - &block_values.difficulty.to_le_bytes(), - rpi_bytes_keccakrlc, + region, + &block_values.difficulty.to_le_bytes(), + rpi_bytes_keccakrlc, rpi_bytes, - rpi_bytes_length_acc, - challenges, + rpi_bytes_length_acc, + challenges, )?; block_copy_cells.push((block_cell, rpi_value_rlc_cell)); block_table_offset += 1; // base_fee - let base_fee = challenges.evm_word().zip( - Value::known(block_values.base_fee.to_le_bytes()) - ).map(|(r, bytes)| rlc(bytes, r)); + let base_fee = challenges + .evm_word() + .zip(Value::known(block_values.base_fee.to_le_bytes())) + .map(|(r, bytes)| rlc(bytes, r)); let block_cell = region.assign_advice( || "base_fee", self.block_table.value, @@ -1444,12 +1502,12 @@ impl PiCircuitConfig { || base_fee, )?; let (_, rpi_value_rlc_cell, _) = self.assign_raw_bytes( - region, - &block_values.base_fee.to_le_bytes(), - rpi_bytes_keccakrlc, + region, + &block_values.base_fee.to_le_bytes(), + rpi_bytes_keccakrlc, rpi_bytes, - rpi_bytes_length_acc, - challenges, + rpi_bytes_length_acc, + challenges, )?; block_copy_cells.push((block_cell, rpi_value_rlc_cell)); block_table_offset += 1; @@ -1462,20 +1520,21 @@ impl PiCircuitConfig { || Value::known(F::from(block_values.chain_id)), )?; let (_, rpi_value_rlc_cell, _) = self.assign_raw_bytes( - region, - &block_values.chain_id.to_be_bytes(), - rpi_bytes_keccakrlc, + region, + &block_values.chain_id.to_be_bytes(), + rpi_bytes_keccakrlc, rpi_bytes, - rpi_bytes_length_acc, - challenges, + rpi_bytes_length_acc, + challenges, )?; block_copy_cells.push((chainid_cell, rpi_value_rlc_cell)); block_table_offset += 1; for prev_hash in block_values.history_hashes { - let prev_hash_rlc = challenges.evm_word().zip( - Value::known(prev_hash.to_fixed_bytes()) - ).map(|(r, bytes)| rlc(bytes, r)); + let prev_hash_rlc = challenges + .evm_word() + .zip(Value::known(prev_hash.to_fixed_bytes())) + .map(|(r, bytes)| rlc(bytes, r)); let block_cell = region.assign_advice( || "prev_hash", @@ -1484,20 +1543,20 @@ impl PiCircuitConfig { || prev_hash_rlc, )?; let (_, rpi_value_rlc_cell, _) = self.assign_raw_bytes( - region, - &prev_hash.to_fixed_bytes(), - rpi_bytes_keccakrlc, + region, + &prev_hash.to_fixed_bytes(), + rpi_bytes_keccakrlc, rpi_bytes, - rpi_bytes_length_acc, - challenges, + rpi_bytes_length_acc, + challenges, )?; block_copy_cells.push((block_cell, rpi_value_rlc_cell)); block_table_offset += 1; } - block_copy_cells.iter().try_for_each(|(left, right)| { - region.constrain_equal(left.cell(), right.cell()) - })?; + block_copy_cells + .iter() + .try_for_each(|(left, right)| region.constrain_equal(left.cell(), right.cell()))?; Ok(()) } @@ -1528,22 +1587,22 @@ impl PiCircuitConfig { // block state root self.assign_raw_bytes( - region, - &extra.state_root.to_fixed_bytes(), - rpi_bytes_keccakrlc, + region, + &extra.state_root.to_fixed_bytes(), + rpi_bytes_keccakrlc, rpi_bytes, - rpi_bytes_length_acc, - challenges, + rpi_bytes_length_acc, + challenges, )?; - + // previous block state root self.assign_raw_bytes( - region, - &extra.prev_state_root.to_fixed_bytes(), - rpi_bytes_keccakrlc, + region, + &extra.prev_state_root.to_fixed_bytes(), + rpi_bytes_keccakrlc, rpi_bytes, - rpi_bytes_length_acc, - challenges, + rpi_bytes_length_acc, + challenges, )?; Ok(()) @@ -1556,7 +1615,7 @@ impl PiCircuitConfig { region: &mut Region<'_, F>, digest: H256, challenges: &Challenges>, - ) -> Result<(AssignedCell, AssignedCell, AssignedCell), Error>{ + ) -> Result<(AssignedCell, AssignedCell, AssignedCell), Error> { let circuit_len = self.circuit_len(); let challenge = challenges.evm_word(); let mut cells = vec![]; @@ -1567,14 +1626,14 @@ impl PiCircuitConfig { |(mut rpi_digest_lc_acc, mut rpi_digest_rlc_acc), (i, byte)| { rpi_digest_rlc_acc = rpi_digest_rlc_acc.zip(challenge) .and_then(|(acc, rand)| Value::known(acc * rand + F::from(*byte as u64))); - + region.assign_fixed( || "q_digest_value_start", self.q_digest_value_start, i, || Value::known(if i == 0 || i == 16 {F::one()} else {F::zero()}), )?; - + // index 0-15 belong to `hi` bytes // index 16-31 belong to `lo` bytes if i == 16 { @@ -1611,7 +1670,7 @@ impl PiCircuitConfig { self.rpi_digest_bytes_rlc, i, || rpi_digest_rlc_acc, - )?; + )?; if i == 31 { // rlc cell cells.push(rpi_digest_bytes_rlc_cell); } @@ -1620,7 +1679,6 @@ impl PiCircuitConfig { })?; Ok((cells[0].clone(), cells[1].clone(), cells[2].clone())) } - } /// Public Inputs Circuit @@ -1635,11 +1693,7 @@ pub struct PiCircuit { impl PiCircuit { /// Creates a new PiCircuit - pub fn new( - max_txs: usize, - max_calldata: usize, - public_data: PublicData, - ) -> Self { + pub fn new(max_txs: usize, max_calldata: usize, public_data: PublicData) -> Self { Self { max_txs, max_calldata, @@ -1689,22 +1743,15 @@ impl SubCircuit for PiCircuit { /// Compute the public inputs for this circuit. fn instance(&self) -> Vec> { - let rpi_digest_byte_field = get_rpi_digest_byte_field::( - self.max_txs, - self.max_calldata, - &self.public_data, - ); + let rpi_digest_byte_field = + get_rpi_digest_byte_field::(self.max_txs, self.max_calldata, &self.public_data); - let hi_digest = (0..16).fold( - F::zero(), - |acc, i| { - acc * F::from(BYTE_POW_BASE) + rpi_digest_byte_field[i] + let hi_digest = (0..16).fold(F::zero(), |acc, i| { + acc * F::from(BYTE_POW_BASE) + rpi_digest_byte_field[i] }); - let lo_digest = (16..32).fold( - F::zero(), - |acc, i| { - acc * F::from(BYTE_POW_BASE) + rpi_digest_byte_field[i] + let lo_digest = (16..32).fold(F::zero(), |acc, i| { + acc * F::from(BYTE_POW_BASE) + rpi_digest_byte_field[i] }); // let block_hash = public_data @@ -1749,6 +1796,7 @@ impl SubCircuit for PiCircuit { region.name_column(|| "q_digest_value_start", config.q_digest_value_start); region.name_column(|| "rpi_bytes", config.rpi_bytes); region.name_column(|| "rpi_bytes_keccakrlc", config.rpi_bytes_keccakrlc); + region.name_column(|| "rpi_value_rlc", config.rpi_value_rlc); region.name_column(|| "rpi_bytes_length_acc", config.rpi_bytes_length_acc); region.name_column(|| "rpi_digest_bytes", config.rpi_digest_bytes); region.name_column(|| "rpi_digest_bytes_lc", config.rpi_digest_bytes_lc); @@ -1767,7 +1815,7 @@ impl SubCircuit for PiCircuit { let mut rpi_bytes = vec![0u8; circuit_len]; let mut rpi_bytes_keccakrlc = Value::known(F::zero()); - let mut rpi_bytes_length_acc:usize = 1; + let mut rpi_bytes_length_acc: usize = 1; // Assign block table let block_values = self.public_data.get_block_table_values(); @@ -1791,9 +1839,11 @@ impl SubCircuit for PiCircuit { &mut rpi_bytes_length_acc, &mut rpi_bytes, )?; - assert_eq!(rpi_bytes_length_acc - 1 , N_BYTES_ZERO + N_BYTES_BLOCK + N_BYTES_EXTRA_VALUE); + assert_eq!( + rpi_bytes_length_acc - 1, + N_BYTES_ZERO + N_BYTES_BLOCK + N_BYTES_EXTRA_VALUE + ); - println!("before entering tx {:?}, N_BYTES_TX = {:?}", rpi_bytes_length_acc, N_BYTES_TX); let mut tx_table_offset = 0; // Assign Tx table let txs = self.public_data.get_tx_table_values(); @@ -1815,89 +1865,78 @@ impl SubCircuit for PiCircuit { )?; tx_table_offset += 1; - iter::empty().chain( - &txs - ).chain( - (0..(config.max_txs - txs.len())).into_iter().map(|_| &tx_default) - ).enumerate().try_for_each(|(i, tx)| -> Result<(), Error> { - // TODO: make TxSignHash as witness - for (tag, value_bytes) in &[ - ( - TxFieldTag::Nonce, - tx.nonce.to_le_bytes().to_vec(), - ), - ( - TxFieldTag::Gas, - tx.gas_limit.to_le_bytes().to_vec(), - ), - ( - TxFieldTag::GasPrice, - tx.gas_price.to_le_bytes().to_vec(), - ), - ( - TxFieldTag::CallerAddress, - tx.from_addr.as_fixed_bytes().to_vec(), - ), - ( - TxFieldTag::CalleeAddress, - tx.to_addr.as_fixed_bytes().to_vec(), - ), - ( - TxFieldTag::IsCreate, - tx.is_create.to_be_bytes().to_vec(), - ), - ( - TxFieldTag::Value, - tx.value.to_le_bytes().to_vec(), - ), - ( - TxFieldTag::CallDataLength, - tx.call_data_len.to_be_bytes().to_vec(), - ), - ( - TxFieldTag::CallDataGasCost, - tx.call_data_gas_cost.to_be_bytes().to_vec(), - ), - ( - TxFieldTag::TxSignHash, - tx.tx_sign_hash.to_vec() - ), - ] { - let i: u64 = i.try_into().unwrap(); - // assign tx field - config.assign_tx_row( - &mut region, - tx_table_offset, - i + 1, - *tag, - 0, - value_bytes, - &mut rpi_bytes_keccakrlc, - _challenges, - &mut rpi_bytes_length_acc, - &mut rpi_bytes, - )?; - tx_table_offset += 1; - } - Ok(()) - })?; - assert_eq!(rpi_bytes_length_acc - 1 , N_BYTES_ZERO - + N_BYTES_BLOCK - + N_BYTES_EXTRA_VALUE - + Self::Config::circuit_len_tx_id(config.max_txs) - + Self::Config::circuit_len_tx_index(config.max_txs) - + Self::Config::circuit_len_tx_values(config.max_txs)); - - println!("before entering call data {:?}", rpi_bytes_length_acc); + iter::empty() + .chain(&txs) + .chain( + (0..(config.max_txs - txs.len())) + .into_iter() + .map(|_| &tx_default), + ) + .enumerate() + .try_for_each(|(i, tx)| -> Result<(), Error> { + // TODO: make TxSignHash as witness + for (tag, value_bytes) in &[ + (TxFieldTag::Nonce, tx.nonce.to_le_bytes().to_vec()), + (TxFieldTag::Gas, tx.gas_limit.to_le_bytes().to_vec()), + (TxFieldTag::GasPrice, tx.gas_price.to_le_bytes().to_vec()), + ( + TxFieldTag::CallerAddress, + tx.from_addr.as_fixed_bytes().to_vec(), + ), + ( + TxFieldTag::CalleeAddress, + tx.to_addr.as_fixed_bytes().to_vec(), + ), + (TxFieldTag::IsCreate, tx.is_create.to_be_bytes().to_vec()), + (TxFieldTag::Value, tx.value.to_le_bytes().to_vec()), + ( + TxFieldTag::CallDataLength, + tx.call_data_len.to_be_bytes().to_vec(), + ), + ( + TxFieldTag::CallDataGasCost, + tx.call_data_gas_cost.to_be_bytes().to_vec(), + ), + (TxFieldTag::TxSignHash, tx.tx_sign_hash.to_vec()), + ] { + let i: u64 = i.try_into().unwrap(); + // assign tx field + config.assign_tx_row( + &mut region, + tx_table_offset, + i + 1, + *tag, + 0, + value_bytes, + &mut rpi_bytes_keccakrlc, + _challenges, + &mut rpi_bytes_length_acc, + &mut rpi_bytes, + )?; + tx_table_offset += 1; + } + Ok(()) + })?; + assert_eq!( + rpi_bytes_length_acc - 1, + N_BYTES_ZERO + + N_BYTES_BLOCK + + N_BYTES_EXTRA_VALUE + + Self::Config::circuit_len_tx_id(config.max_txs) + + Self::Config::circuit_len_tx_index(config.max_txs) + + Self::Config::circuit_len_tx_values(config.max_txs) + ); + // Tx Table CallData let mut calldata_count = 0; - config.q_calldata_start.enable(&mut region, tx_table_offset)?; + config + .q_calldata_start + .enable(&mut region, tx_table_offset)?; // the call data bytes assignment starts at offset 0 let mut call_data_offset = TX_LEN * self.max_txs + EMPTY_TX_ROW_COUNT; let txs = self.public_data.txs(); for (i, tx) in self.public_data.txs().iter().enumerate() { - println!("inside {:?}", i); let call_data_length = tx.call_data.0.len(); let mut gas_cost = F::zero(); for (index, byte) in tx.call_data.0.iter().enumerate() { @@ -1940,53 +1979,61 @@ impl SubCircuit for PiCircuit { calldata_count += 1; } } - println!("reach here?"); - let mut cells=vec![]; + let mut cells = vec![]; for i in calldata_count..config.max_calldata { - let (rpi_bytes_keccakrlc_cell, rpi_bytes_length_acc_cell) = config.assign_tx_calldata_row( - &mut region, - call_data_offset, - 0, // tx_id - 0, - 0, - &[0u8; 1], - &mut rpi_bytes_keccakrlc, - _challenges, - &mut rpi_bytes_length_acc, - &mut rpi_bytes, - false, - F::zero(), - )?; + let (rpi_bytes_keccakrlc_cell, rpi_bytes_length_acc_cell) = config + .assign_tx_calldata_row( + &mut region, + call_data_offset, + 0, // tx_id + 0, + 0, + &[0u8; 1], + &mut rpi_bytes_keccakrlc, + _challenges, + &mut rpi_bytes_length_acc, + &mut rpi_bytes, + false, + F::zero(), + )?; call_data_offset += 1; - if i == config.max_calldata -1 { + if i == config.max_calldata - 1 { cells.push(rpi_bytes_keccakrlc_cell); cells.push(rpi_bytes_length_acc_cell); } } assert!(cells.len() == 2); - let (rpi_bytes_keccakrlc_cell, rpi_bytes_length_acc_cell) = (cells[0].clone(), cells[1].clone()); - assert_eq!(rpi_bytes_length_acc - 1 , N_BYTES_ZERO - + N_BYTES_BLOCK - + N_BYTES_EXTRA_VALUE - + Self::Config::circuit_len_tx_id(config.max_txs) - + Self::Config::circuit_len_tx_index(config.max_txs) - + Self::Config::circuit_len_tx_values(config.max_txs) - + config.max_calldata + let (rpi_bytes_keccakrlc_cell, rpi_bytes_length_acc_cell) = + (cells[0].clone(), cells[1].clone()); + assert_eq!( + rpi_bytes_length_acc - 1, + N_BYTES_ZERO + + N_BYTES_BLOCK + + N_BYTES_EXTRA_VALUE + + Self::Config::circuit_len_tx_id(config.max_txs) + + Self::Config::circuit_len_tx_index(config.max_txs) + + Self::Config::circuit_len_tx_values(config.max_txs) + + config.max_calldata ); // assign keccak digest - let digest = self.public_data.get_pi_digest(config.max_txs, config.max_calldata); - let (hi_lc_cell, lo_lc_cell, rpi_digest_bytes_rlc_cell) = config.assign_rpi_digest(&mut region, digest, _challenges)?; - // externally also compute rlc value, although it already done in prev step `config.assign_rpi_digest` - // to keep api return type clean - let rpi_digest_rlc_acc = digest.to_fixed_bytes() - .iter() - .fold(Value::known(F::zero()), |acc, byte| { - acc.zip(_challenges.evm_word()) - .and_then(|(acc, rand)| Value::known(acc * rand + F::from(*byte as u64))) - }); - + let digest = self + .public_data + .get_pi_digest(config.max_txs, config.max_calldata); + let (hi_lc_cell, lo_lc_cell, rpi_digest_bytes_rlc_cell) = + config.assign_rpi_digest(&mut region, digest, _challenges)?; + // externally also compute rlc value, although it already done in prev step + // `config.assign_rpi_digest` to keep api return type clean + let rpi_digest_rlc_acc = + digest + .to_fixed_bytes() + .iter() + .fold(Value::known(F::zero()), |acc, byte| { + acc.zip(_challenges.evm_word()).and_then(|(acc, rand)| { + Value::known(acc * rand + F::from(*byte as u64)) + }) + }); // lookup assignment let keccak_offset = rpi_bytes_length_acc - 1; // length start from 1, therefore with offset has 1 diff @@ -1994,22 +2041,14 @@ impl SubCircuit for PiCircuit { // assign last & last +1 to 0 first. // otherwise it will emit CellNotAssigned Error - println!("circuit_len {:?}, keccak_offset {:?}", circuit_len, keccak_offset); - config.assign_empty_row( - &mut region, - keccak_offset, - )?; - config.assign_empty_row( - &mut region, - keccak_offset + 1, - )?; + config.assign_empty_row(&mut region, keccak_offset)?; + config.assign_empty_row(&mut region, keccak_offset + 1)?; // also assign empty to last of TxTable - config.assign_empty_txtable_row( - &mut region, - call_data_offset, - )?; + config.assign_empty_txtable_row(&mut region, call_data_offset)?; - config.q_rpi_keccak_lookup.enable(&mut region, rpi_bytes_length_acc)?; + config + .q_rpi_keccak_lookup + .enable(&mut region, rpi_bytes_length_acc)?; let rpi_bytes_keccakrlc_lookup = region.assign_advice( || "rpi_bytes_keccakrlc", config.rpi_bytes_keccakrlc, @@ -2033,14 +2072,11 @@ impl SubCircuit for PiCircuit { (rpi_bytes_keccakrlc_cell, rpi_bytes_keccakrlc_lookup), (rpi_bytes_length_acc_cell, rpi_bytes_length_acc_lookup), (rpi_digest_bytes_rlc_cell, rpi_digest_rlc_acc_lookup), - ].iter().try_for_each(|(left, right)| { - region.constrain_equal(left.cell(), right.cell()) - })?; + ] + .iter() + .try_for_each(|(left, right)| region.constrain_equal(left.cell(), right.cell()))?; - Ok(vec![ - hi_lc_cell, - lo_lc_cell, - ]) + Ok(vec![hi_lc_cell, lo_lc_cell]) }, )?; @@ -2142,11 +2178,14 @@ impl Circuit let challenges = challenges.values(&mut layouter); // assign keccak table - let rpi_bytes = self.0.public_data.get_pi_bytes(config.max_txs, config.max_calldata); + let rpi_bytes = self + .0 + .public_data + .get_pi_bytes(config.max_txs, config.max_calldata); config .keccak_table .dev_load(&mut layouter, vec![&rpi_bytes], &challenges)?; - + self.0.synthesize_sub(&config, &challenges, &mut layouter) } } diff --git a/zkevm-circuits/src/table.rs b/zkevm-circuits/src/table.rs index 7c4b2f36a6f..7b76161583d 100644 --- a/zkevm-circuits/src/table.rs +++ b/zkevm-circuits/src/table.rs @@ -263,10 +263,10 @@ impl LookupTable for TxTable { fn annotations(&self) -> Vec { vec![ - String::from("tx_id"), - String::from("tag"), - String::from("index"), - String::from("value"), + String::from("txtable_tx_id"), + String::from("txtable_tag"), + String::from("txtable_index"), + String::from("txtable_value"), ] } @@ -471,17 +471,17 @@ impl LookupTable for RwTable { fn annotations(&self) -> Vec { vec![ - String::from("rw_counter"), - String::from("is_write"), - String::from("tag"), - String::from("id"), - String::from("address"), - String::from("field_tag"), - String::from("storage_key"), - String::from("value"), - String::from("value_prev"), - String::from("aux1"), - String::from("aux2"), + String::from("rwtable_rw_counter"), + String::from("rwtable_is_write"), + String::from("rwtable_tag"), + String::from("rwtable_id"), + String::from("rwtable_address"), + String::from("rwtable_field_tag"), + String::from("rwtable_storage_key"), + String::from("rwtable_value"), + String::from("rwtable_value_prev"), + String::from("rwtable_aux1"), + String::from("rwtable_aux2"), ] } } @@ -598,13 +598,13 @@ impl LookupTable for MptTable { fn annotations(&self) -> Vec { vec![ - String::from("address"), - String::from("storage_key"), - String::from("proof_type"), - String::from("new_root"), - String::from("old_root"), - String::from("new_value"), - String::from("old_value"), + String::from("mpttable_address"), + String::from("mpttable_storage_key"), + String::from("mpttable_proof_type"), + String::from("mpttable_new_root"), + String::from("mpttable_old_root"), + String::from("mpttable_new_value"), + String::from("mpttable_old_value"), ] } } @@ -755,11 +755,11 @@ impl LookupTable for BytecodeTable { fn annotations(&self) -> Vec { vec![ - String::from("code_hash"), - String::from("tag"), - String::from("index"), - String::from("is_code"), - String::from("value"), + String::from("bytecodetable_code_hash"), + String::from("bytecodetable_tag"), + String::from("bytecodetable_index"), + String::from("bytecodetable_is_code"), + String::from("bytecodetable_value"), ] } } @@ -856,9 +856,9 @@ impl LookupTable for BlockTable { fn annotations(&self) -> Vec { vec![ - String::from("tag"), - String::from("index"), - String::from("value"), + String::from("block_table_tag"), + String::from("block_table_index"), + String::from("block_table_value"), ] } } @@ -888,10 +888,10 @@ impl LookupTable for KeccakTable { fn annotations(&self) -> Vec { vec![ - String::from("is_enabled"), - String::from("input_rlc"), - String::from("input_len"), - String::from("output_rlc"), + String::from("keccaktable_is_enabled"), + String::from("keccaktable_input_rlc"), + String::from("keccaktable_input_len"), + String::from("keccaktable_output_rlc"), ] } }