diff --git a/aggregator/src/core.rs b/aggregator/src/core.rs index f0bb11a84b..bc21e44982 100644 --- a/aggregator/src/core.rs +++ b/aggregator/src/core.rs @@ -284,7 +284,8 @@ pub(crate) fn extract_hash_cells( keccak_packed_multi::get_input_bytes_col_idx_in_cell_manager() + <KeccakTable as LookupTable<Fr>>::columns(&keccak_config.keccak_table) .len() - - 1; + - 1 + - 2; // exclude last word limbs' columns for (offset, keccak_row) in witness.iter().enumerate() { let row = keccak_config.set_row(&mut region, offset, keccak_row)?; diff --git a/aggregator/src/tests/aggregation.rs b/aggregator/src/tests/aggregation.rs index bac29f28c6..6df4c0f0ad 100644 --- a/aggregator/src/tests/aggregation.rs +++ b/aggregator/src/tests/aggregation.rs @@ -11,8 +11,6 @@ use crate::{ tests::mock_chunk::MockChunkCircuit, ChunkHash, }; -//TODO: renable this test after pi/tx circuit supooort word hi lo feature. -#[ignore = "renable after all circuits support word hi-lo done"] #[test] fn test_aggregation_circuit() { env_logger::init(); diff --git a/gadgets/src/comparator.rs b/gadgets/src/comparator.rs index ce9f395604..2cb1dc83c0 100644 --- a/gadgets/src/comparator.rs +++ b/gadgets/src/comparator.rs @@ -4,7 +4,7 @@ use eth_types::Field; use halo2_proofs::{ circuit::{Chip, Region, Value}, - plonk::{ConstraintSystem, Error, Expression, TableColumn, VirtualCells}, + plonk::{Column, ConstraintSystem, Error, Expression, Fixed, VirtualCells}, poly::Rotation, }; @@ -64,7 +64,7 @@ impl<F: Field, const N_BYTES: usize> ComparatorChip<F, N_BYTES> { q_enable: impl FnOnce(&mut VirtualCells<F>) -> Expression<F> + Clone, lhs: impl FnOnce(&mut VirtualCells<F>) -> Expression<F> + Clone, rhs: impl FnOnce(&mut VirtualCells<F>) -> Expression<F> + Clone, - u8_table: TableColumn, + u8_table: Column<Fixed>, ) -> ComparatorConfig<F, N_BYTES> { let lt_config = LtChip::configure(meta, q_enable.clone(), lhs.clone(), rhs.clone(), u8_table); diff --git a/gadgets/src/less_than.rs b/gadgets/src/less_than.rs index ebde33a37b..b12f8b3158 100644 --- a/gadgets/src/less_than.rs +++ b/gadgets/src/less_than.rs @@ -3,7 +3,7 @@ use eth_types::Field; use halo2_proofs::{ circuit::{Chip, Region, Value}, - plonk::{Advice, Column, ConstraintSystem, Error, Expression, TableColumn, VirtualCells}, + plonk::{Advice, Column, ConstraintSystem, Error, Expression, Fixed, VirtualCells}, poly::Rotation, }; @@ -37,7 +37,9 @@ pub struct LtConfig<F, const N_BYTES: usize> { /// Denotes the bytes representation of the difference between lhs and rhs. pub diff: [Column<Advice>; N_BYTES], /// Denotes the range within which each byte should lie. - pub u8_table: TableColumn, + //pub u8_table: TableColumn, + pub u8_table: Column<Fixed>, + /// Denotes the range within which both lhs and rhs lie. pub range: F, } @@ -68,7 +70,8 @@ impl<F: Field, const N_BYTES: usize> LtChip<F, N_BYTES> { q_enable: impl FnOnce(&mut VirtualCells<'_, F>) -> Expression<F> + Clone, lhs: impl FnOnce(&mut VirtualCells<F>) -> Expression<F>, rhs: impl FnOnce(&mut VirtualCells<F>) -> Expression<F>, - u8_table: TableColumn, + //u8_table: TableColumn, + u8_table: Column<Fixed>, ) -> LtConfig<F, N_BYTES> { let lt = meta.advice_column(); let diff = [(); N_BYTES].map(|_| meta.advice_column()); @@ -94,11 +97,11 @@ impl<F: Field, const N_BYTES: usize> LtChip<F, N_BYTES> { }); for cell_column in diff { - meta.lookup("range check for u8", |meta| { + meta.lookup_any("range check for u8", |meta| { let q_enable = q_enable.clone()(meta); vec![( q_enable * meta.query_advice(cell_column, Rotation::cur()), - u8_table, + meta.query_fixed(u8_table, Rotation::cur()), )] }); } @@ -156,11 +159,12 @@ impl<F: Field, const N_BYTES: usize> LtInstruction<F> for LtChip<F, N_BYTES> { ) -> Result<(), Error> { const RANGE: usize = u8::MAX as usize; - layouter.assign_table( + //layouter.assign_table( + layouter.assign_region( || "load u8 range check table", - |mut table| { + |mut region| { for i in 0..=RANGE { - table.assign_cell( + region.assign_fixed( || "assign cell in fixed column", self.config.u8_table, i, @@ -265,7 +269,7 @@ mod test { let q_enable = meta.complex_selector(); let value = meta.advice_column(); let check = meta.advice_column(); - let u8_table = meta.lookup_table_column(); + let u8_table = meta.fixed_column(); let lt = LtChip::configure( meta, @@ -389,7 +393,7 @@ mod test { let q_enable = meta.complex_selector(); let (value_a, value_b) = (meta.advice_column(), meta.advice_column()); let check = meta.advice_column(); - let u16_table = meta.lookup_table_column(); + let u16_table = meta.fixed_column(); let lt = LtChip::configure( meta, diff --git a/gadgets/src/mul_add.rs b/gadgets/src/mul_add.rs index e10fb58183..9834383a6d 100644 --- a/gadgets/src/mul_add.rs +++ b/gadgets/src/mul_add.rs @@ -19,7 +19,7 @@ use eth_types::{Field, Word, ToU16LittleEndian}; use halo2_proofs::{ circuit::{Region, Value}, - plonk::{Advice, Column, ConstraintSystem, Error, Expression, TableColumn, VirtualCells}, + plonk::{Advice, Column, ConstraintSystem, Error, Expression, Fixed, VirtualCells}, poly::Rotation, }; @@ -46,7 +46,8 @@ pub struct MulAddConfig<F> { /// Sum of the parts higher than 256-bit in the product. pub overflow: Expression<F>, /// Lookup table for LtChips and carry_lo/hi. - pub u16_table: TableColumn, + // pub u16_table: TableColumn, + pub u16_table: Column<Fixed>, /// Range check of a, b which needs to be in [0, 2^64) pub range_check_64: UIntRangeCheckChip<F, { UIntRangeCheckChip::SIZE_U64 }, 8>, /// Range check of c, d which needs to be in [0, 2^128) @@ -118,7 +119,8 @@ impl<F: Field> MulAddChip<F> { pub fn configure( meta: &mut ConstraintSystem<F>, q_enable: impl FnOnce(&mut VirtualCells<'_, F>) -> Expression<F> + Clone, - u16_table: TableColumn, + //u16_table: TableColumn, + u16_table: Column<Fixed>, ) -> MulAddConfig<F> { let col0 = meta.advice_column(); let col1 = meta.advice_column(); @@ -157,9 +159,10 @@ impl<F: Field> MulAddChip<F> { carry_cols.append(&mut carry_hi_cols.clone()); for (col, rot) in carry_cols.into_iter() { - meta.lookup("mul carry range check lo/hi lookup u16", |meta| { + meta.lookup_any("mul carry range check lo/hi lookup u16", |meta| { let q_enable = q_enable.clone()(meta); - vec![(q_enable * meta.query_advice(col, Rotation(rot)), u16_table)] + let u16_expr = meta.query_fixed(u16_table, Rotation::cur()); + vec![(q_enable * meta.query_advice(col, Rotation(rot)), u16_expr)] }); } } @@ -506,7 +509,8 @@ mod test { fn configure(meta: &mut halo2_proofs::plonk::ConstraintSystem<F>) -> Self::Config { let q_enable = meta.complex_selector(); - let u16_table = meta.lookup_table_column(); + //let u16_table = meta.lookup_table_column(); + let u16_table = meta.fixed_column(); let mul_config = MulAddChip::configure(meta, |meta| meta.query_selector(q_enable), u16_table); Self::Config { @@ -522,11 +526,12 @@ mod test { ) -> Result<(), halo2_proofs::plonk::Error> { let chip = MulAddChip::construct(config.mul_config); - layouter.assign_table( + //layouter.assign_table( + layouter.assign_region( || "u16 table", - |mut table| { + |mut region| { for i in 0..=65535 { - table.assign_cell( + region.assign_fixed( || format!("u16 table row {i}"), chip.config.u16_table, i, diff --git a/gadgets/src/range.rs b/gadgets/src/range.rs index 81cdebaba4..4888caca7e 100644 --- a/gadgets/src/range.rs +++ b/gadgets/src/range.rs @@ -10,7 +10,7 @@ use crate::util::Expr; use eth_types::Field; use halo2_proofs::{ circuit::{Chip, Region, Value}, - plonk::{Advice, Column, ConstraintSystem, Error, Expression, TableColumn, VirtualCells}, + plonk::{Advice, Column, ConstraintSystem, Error, Expression, Fixed, VirtualCells}, poly::Rotation, }; @@ -36,7 +36,8 @@ pub struct UIntRangeCheckConfig<F, const N_2BYTE: usize, const N_EXPR: usize> { /// Denotes the little-endian representation of expression in u16. pub u16_repr: [Column<Advice>; N_2BYTE], /// Denotes the u16 lookup table. - pub u16_table: TableColumn, + //pub u16_table: TableColumn, + pub u16_table: Column<Fixed>, _marker: std::marker::PhantomData<F>, } @@ -61,7 +62,8 @@ impl<F: Field, const N_2BYTE: usize, const N_EXPR: usize> UIntRangeCheckChip<F, meta: &mut ConstraintSystem<F>, q_enable: impl FnOnce(&mut VirtualCells<F>) -> Expression<F> + Clone, expressions: impl FnOnce(&mut VirtualCells<F>) -> [Expression<F>; N_EXPR], - u16_table: TableColumn, + //u16_table: TableColumn, + u16_table: Column<Fixed>, ) -> UIntRangeCheckConfig<F, N_2BYTE, N_EXPR> { let u16_repr = [(); N_2BYTE].map(|_| meta.advice_column()); @@ -83,9 +85,10 @@ impl<F: Field, const N_2BYTE: usize, const N_EXPR: usize> UIntRangeCheckChip<F, }); for column in u16_repr { - meta.lookup(concat!("u16 cell range check"), |meta| { + meta.lookup_any(concat!("u16 cell range check"), |meta| { let cell = meta.query_advice(column, Rotation::cur()); - vec![(cell, u16_table)] + let u16_expr = meta.query_fixed(u16_table, Rotation::cur()); + vec![(cell, u16_expr)] }); } diff --git a/zkevm-circuits/src/evm_circuit/execution/calldataload.rs b/zkevm-circuits/src/evm_circuit/execution/calldataload.rs index 6cf8ffe15b..197f22268f 100644 --- a/zkevm-circuits/src/evm_circuit/execution/calldataload.rs +++ b/zkevm-circuits/src/evm_circuit/execution/calldataload.rs @@ -157,8 +157,8 @@ impl<F: Field> ExecutionGadget<F> for CallDataLoadGadget<F> { src_id.expr(), TxContextFieldTag::CallData, Some(src_addr.expr() + idx.expr()), - //Word::from_lo_unchecked(buffer_reader.byte(idx)), - buffer_reader.byte(idx), + Word::from_lo_unchecked(buffer_reader.byte(idx)), + // buffer_reader.byte(idx), ); }, ); diff --git a/zkevm-circuits/src/evm_circuit/execution/end_block.rs b/zkevm-circuits/src/evm_circuit/execution/end_block.rs index ac738933d7..494f0fb556 100644 --- a/zkevm-circuits/src/evm_circuit/execution/end_block.rs +++ b/zkevm-circuits/src/evm_circuit/execution/end_block.rs @@ -121,8 +121,8 @@ impl<F: Field> ExecutionGadget<F> for EndBlockGadget<F> { total_txs.expr() + 1.expr(), TxContextFieldTag::CallerAddress, None, - //Word::zero(), - 0.expr(), + Word::zero(), + // 0.expr(), ); // Since every tx lookup done in the EVM circuit must succeed // and uses a unique tx_id, we know that at diff --git a/zkevm-circuits/src/evm_circuit/execution/end_inner_block.rs b/zkevm-circuits/src/evm_circuit/execution/end_inner_block.rs index b290cffc19..b8ad1b033b 100644 --- a/zkevm-circuits/src/evm_circuit/execution/end_inner_block.rs +++ b/zkevm-circuits/src/evm_circuit/execution/end_inner_block.rs @@ -10,7 +10,7 @@ use crate::{ witness::{Block, Call, ExecStep, Transaction}, }, table::{BlockContextFieldTag, TxFieldTag::BlockNumber}, - //util::word::Word, + util::word::Word, }; use eth_types::Field; use gadgets::util::{not, Expr}; @@ -72,8 +72,8 @@ impl<F: Field> ExecutionGadget<F> for EndInnerBlockGadget<F> { last_tx_id.expr(), BlockNumber, None, - // Word::from_lo_unchecked(cb.curr.state.block_number.expr()), - cb.curr.state.block_number.expr(), + Word::from_lo_unchecked(cb.curr.state.block_number.expr()), + // cb.curr.state.block_number.expr(), ); }); diff --git a/zkevm-circuits/src/evm_circuit/execution/gasprice.rs b/zkevm-circuits/src/evm_circuit/execution/gasprice.rs index c9e16e6564..7a4d594818 100644 --- a/zkevm-circuits/src/evm_circuit/execution/gasprice.rs +++ b/zkevm-circuits/src/evm_circuit/execution/gasprice.rs @@ -11,7 +11,7 @@ use crate::{ }, table::{CallContextFieldTag, TxContextFieldTag}, util::{ - word::{WordCell, WordExpr}, + word::{Word, Word32Cell, WordExpr}, Expr, }, }; @@ -22,9 +22,8 @@ use halo2_proofs::{circuit::Value, plonk::Error}; #[derive(Clone, Debug)] pub(crate) struct GasPriceGadget<F> { tx_id: Cell<F>, - gas_price: WordCell<F>, - // TODO: remove gas_price_rlc in word hi lo stage2 (txtable to word) - gas_price_rlc: Cell<F>, + gas_price: Word32Cell<F>, + // gas_price_rlc: Cell<F>, same_context: SameContextGadget<F>, } @@ -35,8 +34,9 @@ impl<F: Field> ExecutionGadget<F> for GasPriceGadget<F> { fn configure(cb: &mut EVMConstraintBuilder<F>) -> Self { // Query gasprice value - let gas_price = cb.query_word_unchecked(); - let gas_price_rlc = cb.query_cell(); + let gas_price = cb.query_word32(); + // let gas_price_rlc = cb.query_cell(); + let gas_price_rlc = cb.word_rlc(gas_price.limbs.clone().map(|l| l.expr())); // Lookup in call_ctx the TxId let tx_id = cb.call_context(None, CallContextFieldTag::TxId); @@ -45,8 +45,9 @@ impl<F: Field> ExecutionGadget<F> for GasPriceGadget<F> { tx_id.expr(), TxContextFieldTag::GasPrice, None, - //gas_price.to_word(), - gas_price_rlc.expr(), + // gas_price.to_word(), + // gas_price_rlc.expr(), + Word::from_lo_unchecked(gas_price_rlc.expr()), ); // Push the value to the stack @@ -66,7 +67,7 @@ impl<F: Field> ExecutionGadget<F> for GasPriceGadget<F> { Self { tx_id, gas_price, - gas_price_rlc, + //gas_price_rlc, same_context, } } @@ -85,8 +86,8 @@ impl<F: Field> ExecutionGadget<F> for GasPriceGadget<F> { self.tx_id .assign(region, offset, Value::known(F::from(tx.id as u64)))?; - self.gas_price_rlc - .assign(region, offset, region.word_rlc(gas_price))?; + // self.gas_price_rlc + // .assign(region, offset, region.word_rlc(gas_price))?; self.gas_price.assign_u256(region, offset, gas_price)?; diff --git a/zkevm-circuits/src/evm_circuit/execution/origin.rs b/zkevm-circuits/src/evm_circuit/execution/origin.rs index ef7b52592c..a3c2d1bad1 100644 --- a/zkevm-circuits/src/evm_circuit/execution/origin.rs +++ b/zkevm-circuits/src/evm_circuit/execution/origin.rs @@ -10,7 +10,10 @@ use crate::{ witness::{Block, Call, ExecStep, Transaction}, }, table::{CallContextFieldTag, TxContextFieldTag}, - util::{word::WordExpr, Expr}, + util::{ + word::{Word, WordExpr}, + Expr, + }, }; use bus_mapping::evm::OpcodeId; use eth_types::Field; @@ -30,16 +33,18 @@ impl<F: Field> ExecutionGadget<F> for OriginGadget<F> { fn configure(cb: &mut EVMConstraintBuilder<F>) -> Self { let origin = cb.query_account_address(); + // let address_rlc = cb.word_rlc(origin.limbs.clone().map(|l| l.expr())); // Lookup in call_ctx the TxId let tx_id = cb.call_context(None, CallContextFieldTag::TxId); + let address_value = from_bytes::expr(&origin.limbs); // Lookup rw_table -> call_context with tx origin address cb.tx_context_lookup( tx_id.expr(), TxContextFieldTag::CallerAddress, None, // None because unrelated to calldata - //origin.to_word(), used in word hi lo stage2 - from_bytes::expr(&origin.limbs), + //origin.to_word(), + Word::from_lo_unchecked(address_value), ); // Push the value to the stack @@ -78,7 +83,7 @@ impl<F: Field> ExecutionGadget<F> for OriginGadget<F> { self.tx_id .assign(region, offset, Value::known(F::from(tx.id as u64)))?; - // Assign Origin addr RLC. + // Assign Origin addr word. self.origin.assign_u256(region, offset, origin)?; // Assign SameContextGadget witnesses. diff --git a/zkevm-circuits/src/evm_circuit/table.rs b/zkevm-circuits/src/evm_circuit/table.rs index 620f7b1b5b..535a8b32af 100644 --- a/zkevm-circuits/src/evm_circuit/table.rs +++ b/zkevm-circuits/src/evm_circuit/table.rs @@ -229,8 +229,8 @@ pub(crate) enum Lookup<F> { /// field_tag is Calldata, otherwise should be set to 0. index: Expression<F>, /// Value of the field. - // value: Word<Expression<F>>, change to word in stage2 - value: Expression<F>, + value: Word<Expression<F>>, + // value: Expression<F>, }, /// Lookup to read-write table, which contains read-write access records of /// time-aware data. @@ -403,9 +403,9 @@ impl<F: Field> Lookup<F> { id.clone(), field_tag.clone(), index.clone(), - // value.lo(), - // value.hi(), - value.clone(), + value.lo(), + value.hi(), + // value.clone(), ], Self::Rw { counter, diff --git a/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs b/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs index c012c28ab6..60a8443f36 100644 --- a/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs +++ b/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs @@ -799,8 +799,8 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { index: Option<Expression<F>>, ) -> Cell<F> { let cell = self.query_cell(); - //self.tx_context_lookup(id, field_tag, index, Word::from_lo_unchecked(cell.expr())); - self.tx_context_lookup(id, field_tag, index, cell.expr()); + self.tx_context_lookup(id, field_tag, index, Word::from_lo_unchecked(cell.expr())); + // self.tx_context_lookup(id, field_tag, index, cell.expr()); cell } @@ -832,8 +832,8 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { id: Expression<F>, field_tag: TxContextFieldTag, index: Option<Expression<F>>, - //value: Word<Expression<F>>, used in stage2 for tx table to word - value: Expression<F>, + value: Word<Expression<F>>, + //value: Expression<F>, ) { self.add_lookup( "Tx lookup", diff --git a/zkevm-circuits/src/exp_circuit.rs b/zkevm-circuits/src/exp_circuit.rs index afc3582b4c..fc0eba1c26 100644 --- a/zkevm-circuits/src/exp_circuit.rs +++ b/zkevm-circuits/src/exp_circuit.rs @@ -10,7 +10,7 @@ pub use dev::ExpCircuit as TestExpCircuit; use crate::{ evm_circuit::util::constraint_builder::{BaseConstraintBuilder, ConstrainBuilderCommon}, - table::{ExpTable, LookupTable, U16Table}, + table::{ExpTable, LookupTable, UXTable}, util::{Challenges, SubCircuit, SubCircuitConfig}, witness, }; @@ -38,7 +38,8 @@ pub struct ExpCircuitConfig<F> { /// The Exponentiation circuit's table. pub exp_table: ExpTable, /// u16 lookup table, - pub u16_table: U16Table, + // pub u16_table: U16Table, + pub u16_table: UXTable<16>, /// Multiplication gadget for verification of each step. pub mul_gadget: MulAddConfig<F>, /// Multiplication gadget to perform 2*n + k. @@ -50,7 +51,8 @@ pub struct ExpCircuitArgs { /// The Exponentiation circuit's table. pub exp_table: ExpTable, /// u16 lookup table, - pub u16_table: U16Table, + // pub u16_table: U16Table, + pub u16_table: UXTable<16>, } impl<F: Field> SubCircuitConfig<F> for ExpCircuitConfig<F> { @@ -74,7 +76,7 @@ impl<F: Field> SubCircuitConfig<F> for ExpCircuitConfig<F> { meta.query_fixed(exp_table.is_step, Rotation::cur()), ]) }, - u16_table.into(), + u16_table.col, ); let parity_check = MulAddChip::configure( meta, @@ -84,7 +86,7 @@ impl<F: Field> SubCircuitConfig<F> for ExpCircuitConfig<F> { meta.query_fixed(exp_table.is_step, Rotation::cur()), ]) }, - u16_table.into(), + u16_table.col, ); // multiplier <- 2^64 diff --git a/zkevm-circuits/src/exp_circuit/dev.rs b/zkevm-circuits/src/exp_circuit/dev.rs index 1c2114186b..779cae8372 100644 --- a/zkevm-circuits/src/exp_circuit/dev.rs +++ b/zkevm-circuits/src/exp_circuit/dev.rs @@ -2,7 +2,7 @@ pub use super::ExpCircuit; use crate::{ exp_circuit::{ExpCircuitArgs, ExpCircuitConfig}, - table::{ExpTable, U16Table}, + table::{ExpTable, UXTable}, util::{Challenges, SubCircuit, SubCircuitConfig}, }; use eth_types::Field; @@ -24,7 +24,7 @@ impl<F: Field> Circuit<F> for ExpCircuit<F> { fn configure(meta: &mut ConstraintSystem<F>) -> Self::Config { let exp_table = ExpTable::construct(meta); let challenges = Challenges::construct(meta); - let u16_table = U16Table::construct(meta); + let u16_table = UXTable::construct(meta); ( ExpCircuitConfig::new( meta, diff --git a/zkevm-circuits/src/keccak_circuit.rs b/zkevm-circuits/src/keccak_circuit.rs index 67320bdfab..2bc37d6aa2 100644 --- a/zkevm-circuits/src/keccak_circuit.rs +++ b/zkevm-circuits/src/keccak_circuit.rs @@ -950,11 +950,16 @@ impl<F: Field> KeccakCircuitConfig<F> { row.data_rlc, Value::known(F::from(row.length as u64)), row.hash_rlc, - //row.hash.lo(), - //row.hash.hi(), + row.hash.lo(), + row.hash.hi(), ], )?; + // work around to remove last two items(hi + lo parts), avoid to mistake hash output cells + // in method `extract_hash_cells` of aggregation circuit. + res.remove(res.len() - 1); + res.remove(res.len() - 1); + // Cell values for (idx, (bit, column)) in row .cell_values diff --git a/zkevm-circuits/src/pi_circuit.rs b/zkevm-circuits/src/pi_circuit.rs index 73a15814f4..2bc82324b0 100644 --- a/zkevm-circuits/src/pi_circuit.rs +++ b/zkevm-circuits/src/pi_circuit.rs @@ -33,7 +33,7 @@ use crate::{ }, state_circuit::StateCircuitExports, tx_circuit::{CHAIN_ID_OFFSET as CHAIN_ID_OFFSET_IN_TX, TX_HASH_OFFSET, TX_LEN}, - //util::word, + util::word, witness::{self, Block, BlockContext, BlockContexts, Transaction}, }; use bus_mapping::util::read_env_var; @@ -343,8 +343,8 @@ pub struct PiCircuitConfig<F: Field> { rpi_field_bytes: Column<Advice>, // rpi in bytes rpi_field_bytes_acc: Column<Advice>, rpi_rlc_acc: Column<Advice>, // RLC(rpi) as the input to Keccak table - // the input word type to Keccak table, TODO: enable rpi_rlc_acc_word in stage2 - // rpi_rlc_acc_word: word::Word<Column<Advice>>, + // the input word type to Keccak table + rpi_rlc_acc_word: word::Word<Column<Advice>>, rpi_length_acc: Column<Advice>, // columns for padding in block context and tx hashes @@ -423,7 +423,7 @@ impl<F: Field> SubCircuitConfig<F> for PiCircuitConfig<F> { let rpi_bytes_acc = meta.advice_column_in(SecondPhase); // hold the accumulated value of rlc(rpi_bytes, keccak_input) let rpi_rlc_acc = meta.advice_column_in(SecondPhase); - //let rpi_rlc_acc_word = word::Word::new([meta.advice_column(), meta.advice_column()]); + let rpi_rlc_acc_word = word::Word::new([meta.advice_column(), meta.advice_column()]); // hold the accumulated length of rpi_bytes for looking into keccak table let rpi_length_acc = meta.advice_column(); @@ -465,9 +465,12 @@ impl<F: Field> SubCircuitConfig<F> for PiCircuitConfig<F> { meta.enable_equality(real_rpi); meta.enable_equality(block_table.value); // copy block to rpi meta.enable_equality(block_table.index); - meta.enable_equality(tx_table.value); // copy tx hashes to rpi + meta.enable_equality(tx_table.value.lo()); // copy tx hashes to rpi + meta.enable_equality(tx_table.value.hi()); // copy tx hashes to rpi meta.enable_equality(cum_num_txs); meta.enable_equality(pi); + meta.enable_equality(rpi_rlc_acc_word.lo()); + meta.enable_equality(rpi_rlc_acc_word.hi()); // 1. constrain rpi_bytes, rpi_bytes_acc, and rpi for each field meta.create_gate( @@ -638,33 +641,32 @@ impl<F: Field> SubCircuitConfig<F> for PiCircuitConfig<F> { // q_keccak = 1 |pi_bs_rlc| .. | ... | pi_hash_rlc | 136 | // pi hash | hi | .. | ... | ... | 16 | // | lo | .. | ... | pi_hash_rlc | 32 | - // TODO: enable this lookup in stage2 - // meta.lookup_any("keccak(rpi)", |meta| { - // let q_keccak = meta.query_selector(q_keccak); - - // let rpi_rlc = meta.query_advice(rpi, Rotation::cur()); - // let rpi_length = meta.query_advice(rpi_length_acc, Rotation::cur()); - // let output = meta.query_advice(rpi_rlc_acc, Rotation::cur()); - // //let output_word = rpi_rlc_acc_word.query_advice(meta, Rotation::cur()); - - // let input_exprs = vec![ - // 1.expr(), // q_enable = true - // 1.expr(), // is_final = true - // rpi_rlc, - // rpi_length, - // output, - // //output_word.lo(), - // //soutput_word.hi(), - // ]; - // let keccak_table_exprs = keccak_table.table_exprs(meta); - // assert_eq!(input_exprs.len(), keccak_table_exprs.len()); - - // input_exprs - // .into_iter() - // .zip(keccak_table_exprs) - // .map(|(input, table)| (q_keccak.expr() * input, table)) - // .collect() - // }); + meta.lookup_any("keccak(rpi)", |meta| { + let q_keccak = meta.query_selector(q_keccak); + + let rpi_rlc = meta.query_advice(rpi, Rotation::cur()); + let rpi_length = meta.query_advice(rpi_length_acc, Rotation::cur()); + let output = meta.query_advice(rpi_rlc_acc, Rotation::cur()); + let output_word = rpi_rlc_acc_word.query_advice(meta, Rotation::cur()); + + let input_exprs = vec![ + 1.expr(), // q_enable = true + 1.expr(), // is_final = true + rpi_rlc, + rpi_length, + output, + output_word.lo(), + output_word.hi(), + ]; + let keccak_table_exprs = keccak_table.table_exprs(meta); + assert_eq!(input_exprs.len(), keccak_table_exprs.len()); + + input_exprs + .into_iter() + .zip(keccak_table_exprs) + .map(|(input, table)| (q_keccak.expr() * input, table)) + .collect() + }); // 3. constrain block_table meta.create_gate( @@ -707,7 +709,7 @@ impl<F: Field> SubCircuitConfig<F> for PiCircuitConfig<F> { rpi_field_bytes: rpi_bytes, rpi_field_bytes_acc: rpi_bytes_acc, rpi_rlc_acc, - //rpi_rlc_acc_word, + rpi_rlc_acc_word, rpi_length_acc, is_rpi_padding, real_rpi, @@ -732,10 +734,10 @@ type PiHashExport<F> = Vec<AssignedCell<F, F>>; #[derive(Debug, Clone)] struct Connections<F: Field> { - //start_state_root: word::Word<AssignedCell<F, F>>, - start_state_root: AssignedCell<F, F>, - //end_state_root: word::Word<AssignedCell<F, F>>, - end_state_root: AssignedCell<F, F>, + start_state_root: word::Word<AssignedCell<F, F>>, + //start_state_root: AssignedCell<F, F>, + end_state_root: word::Word<AssignedCell<F, F>>, + //end_state_root: AssignedCell<F, F>, withdraw_root: AssignedCell<F, F>, } @@ -802,7 +804,7 @@ impl<F: Field> PiCircuitConfig<F> { region: &mut Region<'_, F>, public_data: &PublicData, block_value_cells: &[AssignedCell<F, F>], - tx_value_cells: &[AssignedCell<F, F>], + tx_value_cells: &[word::Word<AssignedCell<F, F>>], challenges: &Challenges<Value<F>>, ) -> Result<(PiHashExport<F>, Connections<F>), Error> { // 1. Assign data bytes. @@ -849,7 +851,7 @@ impl<F: Field> PiCircuitConfig<F> { offset: usize, public_data: &PublicData, block_value_cells: &[AssignedCell<F, F>], - tx_value_cells: &[AssignedCell<F, F>], + tx_value_cells: &[word::Word<AssignedCell<F, F>>], challenges: &Challenges<Value<F>>, ) -> Result<(usize, AssignedCell<F, F>), Error> { // Initialise the RLC accumulator and length values. @@ -983,6 +985,7 @@ impl<F: Field> PiCircuitConfig<F> { rpi_rlc_acc = tmp_rpi_rlc_acc; rpi_length = tmp_rpi_length; tx_copy_cells.push(cells[RPI_CELL_IDX].clone()); + if i == public_data.max_txs - 1 { data_bytes_rlc = Some(cells[RPI_RLC_ACC_CELL_IDX].clone()); data_bytes_length = Some(cells[RPI_LENGTH_ACC_CELL_IDX].clone()); @@ -990,9 +993,10 @@ impl<F: Field> PiCircuitConfig<F> { } // Copy tx_hashes to tx table for (i, tx_hash_cell) in tx_copy_cells.into_iter().enumerate() { + // tx hash value still use rlc format in tx circuit. region.constrain_equal( tx_hash_cell.cell(), - tx_value_cells[i * TX_LEN + TX_HASH_OFFSET - 1].cell(), + tx_value_cells[i * TX_LEN + TX_HASH_OFFSET - 1].lo().cell(), )?; } @@ -1015,6 +1019,15 @@ impl<F: Field> PiCircuitConfig<F> { &public_data.get_data_hash().to_fixed_bytes(), challenges.evm_word(), ); + + let data_hash_word = + word::Word::from(public_data.get_data_hash().to_word()).map(Value::known); + data_hash_word.assign_advice( + region, + || "assign rpi_rlc_acc_word", + self.rpi_rlc_acc_word, + offset, + )?; region.assign_advice( || "data_hash_rlc", self.rpi_rlc_acc, @@ -1037,7 +1050,7 @@ impl<F: Field> PiCircuitConfig<F> { offset: usize, public_data: &PublicData, block_value_cells: &[AssignedCell<F, F>], - tx_value_cells: &[AssignedCell<F, F>], + tx_value_cells: &[word::Word<AssignedCell<F, F>>], data_hash_rlc_cell: &AssignedCell<F, F>, challenges: &Challenges<Value<F>>, ) -> Result<(usize, AssignedCell<F, F>, Connections<F>), Error> { @@ -1068,29 +1081,43 @@ impl<F: Field> PiCircuitConfig<F> { rpi_length, challenges, )?; - Ok(cells[RPI_CELL_IDX].clone()) + Ok((cells[0].clone(), cells[3].clone(), cells[4].clone())) }) .collect::<Result<Vec<_>, Error>>()?; // copy chain_id to block table for block_idx in 0..public_data.max_inner_blocks { region.constrain_equal( - rpi_cells[0].cell(), + rpi_cells[0].0.cell(), block_value_cells[block_idx * BLOCK_LEN + CHAIN_ID_OFFSET].cell(), )?; } // copy chain_id to tx table for tx_id in 0..public_data.max_txs { + // region.constrain_equal( + // rpi_cells[0].0.cell(), + // tx_value_cells[tx_id * TX_LEN + CHAIN_ID_OFFSET_IN_TX - 1].cell(), + // )?; region.constrain_equal( - rpi_cells[0].cell(), - tx_value_cells[tx_id * TX_LEN + CHAIN_ID_OFFSET_IN_TX - 1].cell(), + rpi_cells[0].1.cell(), + tx_value_cells[tx_id * TX_LEN + CHAIN_ID_OFFSET_IN_TX - 1] + .lo() + .cell(), + )?; + region.constrain_equal( + rpi_cells[0].2.cell(), + tx_value_cells[tx_id * TX_LEN + CHAIN_ID_OFFSET_IN_TX - 1] + .hi() + .cell(), )?; } // connections to be done with other sub-circuits. let connections = Connections { - start_state_root: rpi_cells[1].clone(), - end_state_root: rpi_cells[2].clone(), - withdraw_root: rpi_cells[3].clone(), + //start_state_root: rpi_cells[1].clone(), + start_state_root: word::Word::new([rpi_cells[1].1.clone(), rpi_cells[1].2.clone()]), + // end_state_root: rpi_cells[2].clone(), + end_state_root: word::Word::new([rpi_cells[2].1.clone(), rpi_cells[2].2.clone()]), + withdraw_root: rpi_cells[3].0.clone(), }; // Assign data_hash @@ -1125,6 +1152,14 @@ impl<F: Field> PiCircuitConfig<F> { self.rpi_length_acc, offset, )?; + + let pi_hash_word = word::Word::from(public_data.get_pi().to_word()).map(Value::known); + pi_hash_word.assign_advice( + region, + || "assign rpi_rlc_acc_word", + self.rpi_rlc_acc_word, + offset, + )?; let pi_hash_rlc_cell = { let pi_hash_rlc = rlc_be_bytes( &public_data.get_pi().to_fixed_bytes(), @@ -1165,7 +1200,7 @@ impl<F: Field> PiCircuitConfig<F> { challenges, )?; (offset, rpi_rlc_acc, rpi_length) = (tmp_offset, tmp_rpi_rlc_acc, tmp_rpi_length); - let pi_hash_hi_cells = cells[3..].to_vec(); + let pi_hash_hi_cells = cells[5..].to_vec(); // the low 16 bytes of keccak output let (tmp_offset, _, _, cells) = self.assign_field( @@ -1179,7 +1214,7 @@ impl<F: Field> PiCircuitConfig<F> { challenges, )?; offset = tmp_offset; - let pi_hash_lo_cells = cells[3..].to_vec(); + let pi_hash_lo_cells = cells[5..].to_vec(); // Copy pi_hash value we collected from assigning pi bytes. region.constrain_equal(pi_hash_rlc_cell.cell(), cells[RPI_RLC_ACC_CELL_IDX].cell())?; @@ -1254,7 +1289,6 @@ impl<F: Field> PiCircuitConfig<F> { F::zero(), )?; - //let rpi_rlc_acc_word = word::Word::new([F::zero(), F::zero()]); region.assign_advice_from_constant( || "rpi_length_acc[0]", self.rpi_length_acc, @@ -1320,9 +1354,13 @@ impl<F: Field> PiCircuitConfig<F> { self.q_field_step.enable(region, q_offset)?; } - let (mut final_rpi_cell, mut final_rpi_rlc_cell, mut final_rpi_length_cell) = - (None, None, None); - let cells = + let ( + mut final_rpi_cell, + mut final_rpi_rlc_cell, + mut final_rpi_word_cells, + mut final_rpi_length_cell, + ) = (None, None, None, None); + let cells: Vec<(AssignedCell<F, F>, (AssignedCell<F, F>, AssignedCell<F, F>))> = value_be_bytes .iter() .zip(rpi_bytes_acc.iter()) @@ -1386,6 +1424,30 @@ impl<F: Field> PiCircuitConfig<F> { row_offset, || rpi_rlc_acc, )?; + + let rpi_word = if value_be_bytes.len() >= 32 { + let value_word = Word::from_big_endian(&value_be_bytes[..32]); + word::Word::from(value_word).map(Value::known) + } else { + // no meaningful, just for final_rpi_word_cells dummy value + let len = value_be_bytes.len(); + let zero_iter = std::iter::repeat(0); // 生成一个无限重复0的迭代器 + let value_bytes_with_zero = zero_iter + .take(32 - len) + .chain(value_be_bytes.to_vec()) + .collect::<Vec<u8>>(); + // pad zero and take 32 bytes + let value_word = Word::from_big_endian(&value_bytes_with_zero[..32]); + word::Word::from(value_word).map(Value::known) + }; + + final_rpi_word_cells = Some(rpi_word.assign_advice( + region, + || "assign rpi_rlc_acc_word", + self.rpi_rlc_acc_word, + row_offset, + )?); + let rpi_length_cell = region.assign_advice( || "rpi_length_acc", self.rpi_length_acc, @@ -1452,6 +1514,7 @@ impl<F: Field> PiCircuitConfig<F> { // ... // byte_cell[n_bytes - 1] // ] + let final_rpi_word_cells_unwrap = final_rpi_word_cells.unwrap(); Ok(( offset + n_bytes, rpi_rlc_acc, @@ -1461,6 +1524,8 @@ impl<F: Field> PiCircuitConfig<F> { final_rpi_cell.unwrap(), final_rpi_rlc_cell.unwrap(), final_rpi_length_cell.unwrap(), + final_rpi_word_cells_unwrap.lo(), + final_rpi_word_cells_unwrap.hi(), ], byte_cells, ] @@ -1627,7 +1692,8 @@ pub struct PiCircuit<F: Field> { _marker: PhantomData<F>, connections: RefCell<Option<Connections<F>>>, - tx_value_cells: RefCell<Option<Vec<AssignedCell<F, F>>>>, + #[allow(clippy::type_complexity)] + tx_value_cells: RefCell<Option<Vec<word::Word<AssignedCell<F, F>>>>>, } impl<F: Field> PiCircuit<F> { @@ -1679,7 +1745,7 @@ impl<F: Field> PiCircuit<F> { } /// Import tx value cells from Tx circuit - pub fn import_tx_values(&self, values: Vec<AssignedCell<F, F>>) { + pub fn import_tx_values(&self, values: Vec<word::Word<AssignedCell<F, F>>>) { *self.tx_value_cells.borrow_mut() = Some(values); } @@ -1706,15 +1772,22 @@ impl<F: Field> PiCircuit<F> { (&state_roots.start_state_root, &state_roots.end_state_root) ); - // TODO: enable this constraint later after pi circuit, tx circuit updated - // region.constrain_equal( - // local_conn.start_state_root.cell(), - // state_roots.start_state_root.0, - // )?; - // region.constrain_equal( - // local_conn.end_state_root.cell(), - // state_roots.end_state_root.0, - // )?; + region.constrain_equal( + local_conn.start_state_root.lo().cell(), + state_roots.start_state_root.0.lo(), + )?; + region.constrain_equal( + local_conn.start_state_root.hi().cell(), + state_roots.start_state_root.0.hi(), + )?; + region.constrain_equal( + local_conn.end_state_root.lo().cell(), + state_roots.end_state_root.0.lo(), + )?; + region.constrain_equal( + local_conn.end_state_root.hi().cell(), + state_roots.end_state_root.0.hi(), + )?; } else { log::warn!("state roots are not set, skip connection with state circuit"); } diff --git a/zkevm-circuits/src/rlp_circuit_fsm.rs b/zkevm-circuits/src/rlp_circuit_fsm.rs index 8218d23133..de9d6df3c3 100644 --- a/zkevm-circuits/src/rlp_circuit_fsm.rs +++ b/zkevm-circuits/src/rlp_circuit_fsm.rs @@ -7,7 +7,7 @@ mod test; use crate::{ evm_circuit::util::constraint_builder::{BaseConstraintBuilder, ConstrainBuilderCommon}, - table::{LookupTable, RlpFsmRlpTable, U8Table}, + table::{LookupTable, RlpFsmRlpTable, UXTable}, util::{ is_zero::{IsZeroChip, IsZeroConfig}, Challenges, SubCircuit, SubCircuitConfig, @@ -284,7 +284,8 @@ pub struct RlpCircuitConfig<F> { /// ROM table rom_table: RlpFsmRomTable, /// Range u8 table - u8_table: U8Table, + // u8_table: U8Table, + u8_table: UXTable<8>, } impl<F: Field> RlpCircuitConfig<F> { @@ -293,7 +294,8 @@ impl<F: Field> RlpCircuitConfig<F> { meta: &mut ConstraintSystem<F>, rom_table: RlpFsmRomTable, data_table: RlpFsmDataTable, - u8_table: U8Table, + //u8_table: U8Table, + u8_table: UXTable<8>, rlp_table: RlpFsmRlpTable, challenges: &Challenges<Expression<F>>, ) -> Self { @@ -562,7 +564,7 @@ impl<F: Field> RlpCircuitConfig<F> { cb.gate(meta.query_fixed(q_enabled, Rotation::cur())) }); - meta.lookup("byte value check", |meta| { + meta.lookup_any("byte value check", |meta| { let cond = and::expr([ meta.query_fixed(q_enabled, Rotation::cur()), not::expr(is_padding_in_dt.expr(Rotation::cur())(meta)), @@ -570,7 +572,7 @@ impl<F: Field> RlpCircuitConfig<F> { vec![( cond * meta.query_advice(data_table.byte_value, Rotation::cur()), - u8_table.into(), + meta.query_fixed(u8_table.col, Rotation::cur()), )] }); @@ -643,7 +645,7 @@ impl<F: Field> RlpCircuitConfig<F> { cmp_enabled, |meta| meta.query_advice(byte_value, Rotation::cur()), |_| $value.expr(), - u8_table.into(), + u8_table.col, ); }; } @@ -654,7 +656,7 @@ impl<F: Field> RlpCircuitConfig<F> { cmp_enabled, |_| $value.expr(), |meta| meta.query_advice(byte_value, Rotation::cur()), - u8_table.into(), + u8_table.col, ); }; } @@ -737,21 +739,21 @@ impl<F: Field> RlpCircuitConfig<F> { cmp_enabled, |meta| meta.query_advice(tag_idx, Rotation::cur()), |meta| meta.query_advice(tag_length, Rotation::cur()), - u8_table.into(), + u8_table.col, ); let mlength_lte_0x20 = ComparatorChip::configure( meta, cmp_enabled, |meta| meta.query_advice(max_length, Rotation::cur()), |_meta| 0x20.expr(), - u8_table.into(), + u8_table.col, ); let tlength_lte_mlength = ComparatorChip::configure( meta, cmp_enabled, |meta| meta.query_advice(tag_length, Rotation::cur()), |meta| meta.query_advice(max_length, Rotation::cur()), - u8_table.into(), + u8_table.col, ); let depth_check = IsEqualChip::configure( meta, @@ -1894,7 +1896,8 @@ pub struct RlpCircuitConfigArgs<F: Field> { /// RLP table. pub rlp_table: RlpFsmRlpTable, /// u8 table - pub u8_table: U8Table, + // pub u8_table: U8Table, + pub u8_table: UXTable<8>, /// Challenge API. pub challenges: Challenges<Expression<F>>, } diff --git a/zkevm-circuits/src/rlp_circuit_fsm/dev.rs b/zkevm-circuits/src/rlp_circuit_fsm/dev.rs index ec775f397c..f2fc56f943 100644 --- a/zkevm-circuits/src/rlp_circuit_fsm/dev.rs +++ b/zkevm-circuits/src/rlp_circuit_fsm/dev.rs @@ -1,6 +1,6 @@ use crate::{ rlp_circuit_fsm::{RlpCircuit, RlpCircuitConfig, RlpCircuitConfigArgs}, - table::{RlpFsmRlpTable, U8Table}, + table::{RlpFsmRlpTable, UXTable}, util::{Challenges, SubCircuit, SubCircuitConfig}, witness::Transaction, }; @@ -23,8 +23,9 @@ impl<F: Field> Circuit<F> for RlpCircuit<F, Transaction> { fn configure(meta: &mut ConstraintSystem<F>) -> Self::Config { let rlp_table = RlpFsmRlpTable::construct(meta); let challenges = Challenges::construct(meta); - let challenge_exprs = challenges.exprs(meta); - let u8_table = U8Table::construct(meta); + let challenge_exprs: Challenges<halo2_proofs::plonk::Expression<F>> = + challenges.exprs(meta); + let u8_table = UXTable::construct(meta); let config = RlpCircuitConfig::new( meta, diff --git a/zkevm-circuits/src/sig_circuit.rs b/zkevm-circuits/src/sig_circuit.rs index 62a83f605f..5676590fa4 100644 --- a/zkevm-circuits/src/sig_circuit.rs +++ b/zkevm-circuits/src/sig_circuit.rs @@ -22,12 +22,12 @@ use crate::{ keccak_circuit::KeccakCircuit, sig_circuit::ecdsa::ecdsa_verify_no_pubkey_check, table::{KeccakTable, SigTable}, - util::{Challenges, Expr, SubCircuit, SubCircuitConfig}, + util::{word, Challenges, Expr, SubCircuit, SubCircuitConfig}, }; use eth_types::{ self, sign_types::{pk_bytes_le, pk_bytes_swap_endianness, SignData}, - Field, + Field, Word, }; use halo2_base::{ gates::{range::RangeConfig, GateInstructions, RangeInstructions}, @@ -58,7 +58,7 @@ use halo2_proofs::{ use ethers_core::utils::keccak256; use itertools::Itertools; use log::error; -use std::{iter, marker::PhantomData}; +use std::{iter, iter::Iterator, marker::PhantomData, vec::Vec}; /// Circuit configuration arguments pub struct SigCircuitConfigArgs<F: Field> { @@ -77,6 +77,8 @@ pub struct SigCircuitConfig<F: Field> { ecdsa_config: FpChip<F>, /// An advice column to store RLC witnesses rlc_column: Column<Advice>, + /// An advice column to store word keccak result + rlc_column_word: word::Word<Column<Advice>>, /// selector for keccak lookup table q_keccak: Selector, /// Used to lookup pk->pk_hash(addr) @@ -143,7 +145,7 @@ impl<F: Field> SubCircuitConfig<F> for SigCircuitConfig<F> { let rlc_column = meta.advice_column_in(halo2_proofs::plonk::FirstPhase); #[cfg(not(feature = "onephase"))] let rlc_column = meta.advice_column_in(halo2_proofs::plonk::SecondPhase); - + let rlc_column_word = word::Word::new([meta.advice_column(), meta.advice_column()]); meta.enable_equality(rlc_column); meta.enable_equality(sig_table.recovered_addr); @@ -152,6 +154,8 @@ impl<F: Field> SubCircuitConfig<F> for SigCircuitConfig<F> { meta.enable_equality(sig_table.sig_v); meta.enable_equality(sig_table.is_valid); meta.enable_equality(sig_table.msg_hash_rlc); + // meta.enable_equality(sig_table.msg_hash_word.lo()); + // meta.enable_equality(sig_table.msg_hash_word.hi()); // Ref. spec SignVerifyChip 1. Verify that keccak(pub_key_bytes) = pub_key_hash // by keccak table lookup, where pub_key_bytes is built from the pub_key @@ -177,7 +181,9 @@ impl<F: Field> SubCircuitConfig<F> for SigCircuitConfig<F> { is_enable.clone(), is_enable.clone() * meta.query_advice(rlc_column, Rotation(1)), is_enable.clone() * 64usize.expr(), - is_enable * meta.query_advice(rlc_column, Rotation(2)), + is_enable.clone() * meta.query_advice(rlc_column, Rotation(2)), + is_enable.clone() * meta.query_advice(rlc_column_word.lo(), Rotation::cur()), + is_enable * meta.query_advice(rlc_column_word.hi(), Rotation::cur()), ]; let table = [ meta.query_fixed(keccak_table.q_enable, Rotation::cur()), @@ -185,6 +191,8 @@ impl<F: Field> SubCircuitConfig<F> for SigCircuitConfig<F> { meta.query_advice(keccak_table.input_rlc, Rotation::cur()), meta.query_advice(keccak_table.input_len, Rotation::cur()), meta.query_advice(keccak_table.output_rlc, Rotation::cur()), + meta.query_advice(keccak_table.output.lo(), Rotation::cur()), + meta.query_advice(keccak_table.output.hi(), Rotation::cur()), ]; input.into_iter().zip(table).collect() @@ -196,6 +204,7 @@ impl<F: Field> SubCircuitConfig<F> for SigCircuitConfig<F> { sig_table, q_keccak, rlc_column, + rlc_column_word, } } } @@ -473,6 +482,14 @@ impl<F: Field> SigCircuit<F> { offset, || is_address_zero.value, )?; + let word_zero = word::Word::new([Value::known(F::zero()), Value::known(F::zero())]); + word_zero.assign_advice( + &mut ctx.region, + || "assign rlc_column_word", + config.rlc_column_word, + offset + 1, + )?; + ctx.region .constrain_equal(is_address_zero.cell, tmp_cell.cell())?; @@ -483,6 +500,14 @@ impl<F: Field> SigCircuit<F> { offset + 1, || pk_rlc.value, )?; + + word_zero.assign_advice( + &mut ctx.region, + || "assign rlc_column_word", + config.rlc_column_word, + offset + 2, + )?; + ctx.region.constrain_equal(pk_rlc.cell, tmp_cell.cell())?; // pk_hash_rlc @@ -507,7 +532,7 @@ impl<F: Field> SigCircuit<F> { ecdsa_chip: &FpChip<F>, sign_data: &SignData, assigned_data: &AssignedECDSA<F, FpChip<F>>, - ) -> Result<SignDataDecomposed<F>, Error> { + ) -> Result<(SignDataDecomposed<F>, Word), Error> { // build ecc chip from Fp chip let ecc_chip = EccChip::<F, FpChip<F>>::construct(ecdsa_chip.clone()); @@ -528,6 +553,7 @@ impl<F: Field> SigCircuit<F> { let pk_le = pk_bytes_le(&sign_data.pk); let pk_be = pk_bytes_swap_endianness(&pk_le); let pk_hash = keccak256(pk_be).map(|byte| Value::known(F::from(byte as u64))); + let pk_hash_word = Word::from_big_endian(&keccak256(pk_be)); log::trace!("pk hash {:0x?}", pk_hash); let pk_hash_cells = pk_hash @@ -575,6 +601,7 @@ impl<F: Field> SigCircuit<F> { &byte_cells, &powers_of_256_cells, )?; + Ok(byte_cells) }; @@ -634,15 +661,18 @@ impl<F: Field> SigCircuit<F> { &assigned_data.integer_s, )?; - Ok(SignDataDecomposed { - pk_hash_cells, - msg_hash_cells: assigned_msg_hash_le, - pk_cells: assigned_pk_le_selected, - address, - is_address_zero, - r_cells, - s_cells, - }) + Ok(( + SignDataDecomposed { + pk_hash_cells, + msg_hash_cells: assigned_msg_hash_le, + pk_cells: assigned_pk_le_selected, + address, + is_address_zero, + r_cells, + s_cells, + }, + pk_hash_word, + )) } #[allow(clippy::too_many_arguments)] @@ -710,6 +740,7 @@ impl<F: Field> SigCircuit<F> { evm_challenge_powers.clone(), ); + // TODO:calculate pk hash word [QuantumCell<F>;32] // step 4: r,s rlc let r_rlc = rlc_chip.gate.inner_product( ctx, @@ -737,6 +768,7 @@ impl<F: Field> SigCircuit<F> { s_rlc, v: assigned_ecdsa.v, }; + Ok((to_be_keccak_checked, assigned_sig_verif)) } @@ -759,7 +791,7 @@ impl<F: Field> SigCircuit<F> { let mut first_pass = SKIP_FIRST_PASS; let ecdsa_chip = &config.ecdsa_config; - let assigned_sig_verifs = layouter.assign_region( + let assigned_sig_verifys = layouter.assign_region( || "ecdsa chip verification", |region| { if first_pass { @@ -795,7 +827,7 @@ impl<F: Field> SigCircuit<F> { assigned_ecdsa, ) }) - .collect::<Result<Vec<SignDataDecomposed<F>>, Error>>()?; + .collect::<Result<Vec<(SignDataDecomposed<F>, Word)>, Error>>()?; // IMPORTANT: Move to Phase2 before RLC log::info!("before proceeding to the next phase"); @@ -814,34 +846,38 @@ impl<F: Field> SigCircuit<F> { let (assigned_keccak_values, assigned_sig_values): ( Vec<[AssignedValue<F>; 3]>, Vec<AssignedSignatureVerify<F>>, - ) = signatures - .iter() - .chain(std::iter::repeat(&SignData::default())) - .take(self.max_verif) - .zip_eq(assigned_ecdsas.iter()) - .zip_eq(sign_data_decomposed.iter()) - .map(|((sign_data, assigned_ecdsa), sign_data_decomp)| { - self.assign_sig_verify( - &mut ctx, - &ecdsa_chip.range, - sign_data, - sign_data_decomp, - challenges, - assigned_ecdsa, - ) - }) - .collect::<Result< - Vec<([AssignedValue<F>; 3], AssignedSignatureVerify<F>)>, - Error, - >>()? - .into_iter() - .unzip(); + ) = + signatures + .iter() + .chain(std::iter::repeat(&SignData::default())) + .take(self.max_verif) + .zip_eq(assigned_ecdsas.iter()) + .zip_eq(sign_data_decomposed.iter()) + .map(|((sign_data, assigned_ecdsa), sign_data_decomp)| { + self.assign_sig_verify( + &mut ctx, + &ecdsa_chip.range, + sign_data, + &sign_data_decomp.0, + challenges, + assigned_ecdsa, + ) + }) + .collect::<Result< + Vec<([AssignedValue<F>; 3], AssignedSignatureVerify<F>)>, + Error, + >>()? + .into_iter() + .unzip(); // ================================================ // step 4: deferred keccak checks // ================================================ - for (i, [is_address_zero, pk_rlc, pk_hash_rlc]) in - assigned_keccak_values.iter().enumerate() + for (i, ([is_address_zero, pk_rlc, pk_hash_rlc], sign_data)) in + assigned_keccak_values + .iter() + .zip_eq(sign_data_decomposed.iter()) + .enumerate() { let offset = i * 3; self.enable_keccak_lookup( @@ -852,6 +888,14 @@ impl<F: Field> SigCircuit<F> { pk_rlc, pk_hash_rlc, )?; + + let pk_hash_word = word::Word::from(sign_data.1).map(Value::known); + pk_hash_word.assign_advice( + &mut ctx.region, + || "assign rlc_column_word", + config.rlc_column_word, + offset, + )?; } // IMPORTANT: this assigns all constants to the fixed columns @@ -871,7 +915,7 @@ impl<F: Field> SigCircuit<F> { || "expose sig table", |mut region| { // step 5: export as a lookup table - for (idx, assigned_sig_verif) in assigned_sig_verifs.iter().enumerate() { + for (idx, assigned_sig_verif) in assigned_sig_verifys.iter().enumerate() { region.assign_fixed( || "assign sig_table selector", config.sig_table.q_enable, @@ -917,7 +961,7 @@ impl<F: Field> SigCircuit<F> { }, )?; - Ok(assigned_sig_verifs) + Ok(assigned_sig_verifys) } /// Assert an CRTInteger's byte representation is correct. diff --git a/zkevm-circuits/src/state_circuit.rs b/zkevm-circuits/src/state_circuit.rs index 505827f85b..4651e54da4 100644 --- a/zkevm-circuits/src/state_circuit.rs +++ b/zkevm-circuits/src/state_circuit.rs @@ -445,18 +445,18 @@ impl<F: Field> StateCircuitConfig<F> { Ok(StateCircuitExports { start_state_root: ( //start_state_root, - word::Word::new([start_state_root.hi().cell(), start_state_root.lo().cell()]), + word::Word::new([start_state_root.lo().cell(), start_state_root.hi().cell()]), word::Word::new([ - start_state_root.hi().value_field(), start_state_root.lo().value_field(), + start_state_root.hi().value_field(), ]), //start_state_root.into_value(), ), end_state_root: ( - word::Word::new([end_state_root.hi().cell(), end_state_root.lo().cell()]), + word::Word::new([end_state_root.lo().cell(), end_state_root.hi().cell()]), word::Word::new([ - end_state_root.hi().value_field(), end_state_root.lo().value_field(), + end_state_root.hi().value_field(), ]), ), }) @@ -672,17 +672,17 @@ impl<F: Field> StateCircuitConfig<F> { Ok(StateCircuitExports { start_state_root: ( - word::Word::new([start_state_root.hi().cell(), start_state_root.lo().cell()]), + word::Word::new([start_state_root.lo().cell(), start_state_root.hi().cell()]), word::Word::new([ - start_state_root.hi().value_field(), start_state_root.lo().value_field(), + start_state_root.hi().value_field(), ]), ), end_state_root: ( - word::Word::new([start_state_root.hi().cell(), start_state_root.lo().cell()]), + word::Word::new([end_state_root.lo().cell(), end_state_root.hi().cell()]), word::Word::new([ - end_state_root.hi().value_field(), end_state_root.lo().value_field(), + end_state_root.hi().value_field(), ]), ), }) diff --git a/zkevm-circuits/src/super_circuit.rs b/zkevm-circuits/src/super_circuit.rs index 22af5a357a..2dc4fca96a 100644 --- a/zkevm-circuits/src/super_circuit.rs +++ b/zkevm-circuits/src/super_circuit.rs @@ -82,7 +82,7 @@ use crate::{ table::{ BlockTable, BytecodeTable, CopyTable, EccTable, ExpTable, KeccakTable, ModExpTable, MptTable, PoseidonTable, PowOfRandTable, RlpFsmRlpTable as RlpTable, RwTable, SHA256Table, - SigTable, TxTable, U16Table, U8Table, UXTable, + SigTable, TxTable, UXTable, }, tx_circuit::{TxCircuit, TxCircuitConfig, TxCircuitConfigArgs}, util::{circuit_stats, log2_ceil, Challenges, SubCircuit, SubCircuitConfig}, @@ -113,10 +113,10 @@ pub struct SuperCircuitConfig<F: Field> { rlp_table: RlpTable, tx_table: TxTable, poseidon_table: PoseidonTable, - u8_table: U8Table, - u16_table: U16Table, + // u8_table: U8Table, + // u16_table: U16Table, ux8_table: UXTable<8>, - u10_table: UXTable<10>, + ux10_table: UXTable<10>, ux16_table: UXTable<16>, evm_circuit: EvmCircuitConfig<F>, state_circuit: StateCircuitConfig<F>, @@ -208,9 +208,9 @@ impl SubCircuitConfig<Fr> for SuperCircuitConfig<Fr> { let pow_of_rand_table = PowOfRandTable::construct(meta, &challenges_expr); log_circuit_info(meta, "power of randomness table"); - let u8_table = U8Table::construct(meta); + // let u8_table = U8Table::construct(meta); // log_circuit_info(meta, "u8 table"); - let u16_table = U16Table::construct(meta); + // let u16_table = U16Table::construct(meta); // log_circuit_info(meta, "u16 table"); let ux8_table = UXTable::construct(meta); @@ -244,7 +244,8 @@ impl SubCircuitConfig<Fr> for SuperCircuitConfig<Fr> { meta, RlpCircuitConfigArgs { rlp_table, - u8_table, + //u8_table, + u8_table: ux8_table, challenges: challenges_expr.clone(), }, ); @@ -269,8 +270,8 @@ impl SubCircuitConfig<Fr> for SuperCircuitConfig<Fr> { keccak_table: keccak_table.clone(), rlp_table, sig_table, - u8_table, - u16_table, + u8_table: ux8_table, + u16_table: ux16_table, challenges: challenges_expr.clone(), }, ); @@ -344,7 +345,7 @@ impl SubCircuitConfig<Fr> for SuperCircuitConfig<Fr> { meta, ExpCircuitArgs { exp_table, - u16_table, + u16_table: ux16_table, }, ); log_circuit_info(meta, "exp circuit"); @@ -402,10 +403,10 @@ impl SubCircuitConfig<Fr> for SuperCircuitConfig<Fr> { tx_table, rlp_table, poseidon_table, - u8_table, + // u8_table, ux8_table, - u10_table, - u16_table, + ux10_table: u10_table, + // u16_table, ux16_table, evm_circuit, state_circuit, @@ -780,8 +781,9 @@ impl< ) -> Result<(), Error> { let challenges = challenges.values(&layouter); - config.u8_table.load(&mut layouter)?; - config.u16_table.load(&mut layouter)?; + config.ux8_table.load(&mut layouter)?; + config.ux10_table.load(&mut layouter)?; + config.ux16_table.load(&mut layouter)?; self.synthesize_sub(&config, &challenges, &mut layouter) } diff --git a/zkevm-circuits/src/table.rs b/zkevm-circuits/src/table.rs index ed9bc313e7..7eb3e355c4 100644 --- a/zkevm-circuits/src/table.rs +++ b/zkevm-circuits/src/table.rs @@ -210,7 +210,8 @@ pub struct TxTable { /// Index for Tag = CallData pub index: Column<Advice>, /// Value - pub value: Column<Advice>, + //pub value: Column<Advice>, + pub value: word::Word<Column<Advice>>, } impl TxTable { @@ -223,7 +224,8 @@ impl TxTable { tx_id: meta.advice_column(), tag, index: meta.advice_column(), - value: meta.advice_column_in(SecondPhase), + //value: meta.advice_column_in(SecondPhase), + value: word::Word::new([meta.advice_column(), meta.advice_column()]), } } @@ -237,7 +239,7 @@ impl TxTable { max_calldata: usize, chain_id: u64, challenges: &Challenges<Value<F>>, - ) -> Result<Vec<AssignedCell<F, F>>, Error> { + ) -> Result<Vec<word::Word<AssignedCell<F, F>>>, Error> { assert!( txs.len() <= max_txs, "txs.len() <= max_txs: txs.len()={}, max_txs={}", @@ -260,10 +262,11 @@ impl TxTable { q_enable: Column<Fixed>, advice_columns: &[Column<Advice>], tag: &Column<Fixed>, - row: &[Value<F>; 4], + row: &[Value<F>; 5], msg: &str, - ) -> Result<AssignedCell<F, F>, Error> { - let mut value_cell = None; + ) -> Result<word::Word<AssignedCell<F, F>>, Error> { + let mut value_cell_lo: Option<AssignedCell<F, F>> = None; + let mut value_cell_hi: Option<AssignedCell<F, F>> = None; for (index, column) in advice_columns.iter().enumerate() { let cell = region.assign_advice( || format!("tx table {msg} row {offset}"), @@ -271,11 +274,15 @@ impl TxTable { offset, || row[if index > 0 { index + 1 } else { index }], )?; - // tx_id, index, value + // tx_id, index, value_lo, value_hi if index == 2 { - value_cell = Some(cell); + value_cell_lo = Some(cell.clone()); + } + if index == 3 { + value_cell_hi = Some(cell); } } + region.assign_fixed( || format!("tx table q_enable row {offset}"), q_enable, @@ -288,7 +295,10 @@ impl TxTable { offset, || row[1], )?; - Ok(value_cell.unwrap()) + Ok(word::Word::new([ + value_cell_lo.unwrap(), + value_cell_hi.unwrap(), + ])) } layouter.assign_region( @@ -296,14 +306,14 @@ impl TxTable { |mut region| { let mut offset = 0; let mut tx_value_cells = vec![]; - let advice_columns = [self.tx_id, self.index, self.value]; + let advice_columns = [self.tx_id, self.index, self.value.lo(), self.value.hi()]; assign_row( &mut region, offset, self.q_enable, &advice_columns, &self.tag, - &[(); 4].map(|_| Value::known(F::zero())), + &[(); 5].map(|_| Value::known(F::zero())), "all-zero", )?; offset += 1; @@ -313,7 +323,7 @@ impl TxTable { // region that has a size parametrized by max_calldata with all // the tx calldata. This is required to achieve a constant fixed column tag // regardless of the number of input txs or the calldata size of each tx. - let mut calldata_assignments: Vec<[Value<F>; 4]> = Vec::new(); + let mut calldata_assignments: Vec<[Value<F>; 5]> = Vec::new(); // Assign Tx data (all tx fields except for calldata) let padding_txs = (txs.len()..max_txs) .map(|tx_id| { @@ -367,7 +377,8 @@ impl<F: Field> LookupTable<F> for TxTable { self.tx_id.into(), self.tag.into(), self.index.into(), - self.value.into(), + self.value.lo().into(), + self.value.hi().into(), ] } @@ -377,7 +388,8 @@ impl<F: Field> LookupTable<F> for TxTable { String::from("tx_id"), String::from("tag"), String::from("index"), - String::from("value"), + String::from("value lo"), + String::from("value hi"), ] } @@ -387,7 +399,8 @@ impl<F: Field> LookupTable<F> for TxTable { meta.query_advice(self.tx_id, Rotation::cur()), meta.query_fixed(self.tag, Rotation::cur()), meta.query_advice(self.index, Rotation::cur()), - meta.query_advice(self.value, Rotation::cur()), + meta.query_advice(self.value.lo(), Rotation::cur()), + meta.query_advice(self.value.hi(), Rotation::cur()), ] } } @@ -1459,7 +1472,7 @@ impl KeccakTable { &self, region: &mut Region<F>, offset: usize, - values: [Value<F>; 4], + values: [Value<F>; 6], ) -> Result<Vec<AssignedCell<F, F>>, Error> { let mut res = vec![]; for (&column, value) in <KeccakTable as LookupTable<F>>::advice_columns(self) @@ -2443,7 +2456,9 @@ pub struct SigTable { /// Indicates whether or not the gates are enabled on the current row. pub q_enable: Column<Fixed>, /// Random-linear combination of the Keccak256 hash of the message that's signed. + /// do not change to word hi lo (msg_hash_word) becuase it is related to ecc chip. pub msg_hash_rlc: Column<Advice>, + // TODO: sig_r_rlc, sig_s_rlc to word as well ? /// should be in range [0, 1] pub sig_v: Column<Advice>, /// Random-linear combination of the signature's `r` component. @@ -2462,6 +2477,7 @@ impl SigTable { Self { q_enable: meta.fixed_column(), msg_hash_rlc: meta.advice_column_in(SecondPhase), + // msg_hash_word: word::Word::new([meta.advice_column(), meta.advice_column()]), sig_v: meta.advice_column(), sig_s_rlc: meta.advice_column_in(SecondPhase), sig_r_rlc: meta.advice_column_in(SecondPhase), @@ -2490,6 +2506,11 @@ impl SigTable { challenge, ) }); + + // let msg_hash_word = + // word::Word::from(Word::from_big_endian(&sign_data.msg_hash.to_bytes())) + // .map(Value::<F>::known); + let sig_r_rlc = evm_word.map(|challenge| { rlc::value( sign_data.signature.0.to_bytes().iter().collect_vec(), @@ -2529,6 +2550,13 @@ impl SigTable { || value, )?; } + + // msg_hash_word.assign_advice( + // &mut region, + // || format!("sig table msg_hash_word {offset}"), + // self.msg_hash_word, + // offset, + // )?; } Ok(()) @@ -2544,6 +2572,8 @@ impl<F: Field> LookupTable<F> for SigTable { vec![ self.q_enable.into(), self.msg_hash_rlc.into(), + // self.msg_hash_word.lo().into(), + // self.msg_hash_word.hi().into(), self.sig_v.into(), self.sig_r_rlc.into(), self.sig_s_rlc.into(), @@ -2556,6 +2586,8 @@ impl<F: Field> LookupTable<F> for SigTable { vec![ String::from("q_enable"), String::from("msg_hash_rlc"), + String::from("msg_hash_word lo"), + String::from("msg_hash_word hi"), String::from("sig_v"), String::from("sig_r_rlc"), String::from("sig_s_rlc"), @@ -3142,7 +3174,9 @@ impl<const MAX: usize> From<RangeTable<MAX>> for TableColumn { /// Lookup table for max n bits range check #[derive(Clone, Copy, Debug)] pub struct UXTable<const N_BITS: usize> { - col: Column<Fixed>, + /// content col in the table + pub col: Column<Fixed>, + // col: TableColumn, } impl<const N_BITS: usize> UXTable<N_BITS> { @@ -3150,14 +3184,17 @@ impl<const N_BITS: usize> UXTable<N_BITS> { pub fn construct<F: Field>(meta: &mut ConstraintSystem<F>) -> Self { Self { col: meta.fixed_column(), + // col: meta.lookup_table_column(), } } /// Load the `UXTable` for range check pub fn load<F: Field>(&self, layouter: &mut impl Layouter<F>) -> Result<(), Error> { + //layouter.assign_table( layouter.assign_region( || format!("assign u{} fixed column", 8), |mut region| { + // |mut table| { for i in 0..(1 << N_BITS) { region.assign_fixed( || format!("assign {i} in u{N_BITS} fixed column"), @@ -3165,6 +3202,12 @@ impl<const N_BITS: usize> UXTable<N_BITS> { i, || Value::known(F::from(i as u64)), )?; + // table.assign_cell( + // || format!("range at offset = {i}"), + // self.col, + // i, + // || Value::known(F::from(i as u64)), + // )?; } Ok(()) }, @@ -3175,6 +3218,7 @@ impl<const N_BITS: usize> UXTable<N_BITS> { impl<F: Field, const N_BITS: usize> LookupTable<F> for UXTable<N_BITS> { fn columns(&self) -> Vec<Column<Any>> { + // vec![self.col.into()] vec![self.col.into()] } @@ -3186,3 +3230,12 @@ impl<F: Field, const N_BITS: usize> LookupTable<F> for UXTable<N_BITS> { vec![meta.query_fixed(self.col, Rotation::cur())] } } + +// impl<const N_BITS: usize> From<UXTable<N_BITS>> for TableColumn { +// fn from(table: UXTable<N_BITS>) -> TableColumn { +// //table.col +// TableColumn { +// inner: table.col, +// } +// } +// } diff --git a/zkevm-circuits/src/tx_circuit.rs b/zkevm-circuits/src/tx_circuit.rs index bd886e5c5c..ce4509e1c7 100644 --- a/zkevm-circuits/src/tx_circuit.rs +++ b/zkevm-circuits/src/tx_circuit.rs @@ -24,11 +24,11 @@ use crate::{ Gas, GasPrice, IsCreate, Nonce, SigR, SigS, SigV, TxDataGasCost, TxHashLength, TxHashRLC, TxSignHash, TxSignLength, TxSignRLC, }, - TxTable, U16Table, U8Table, + TxTable, UXTable, }, util::{ is_zero::{IsZeroChip, IsZeroConfig}, - keccak, rlc_be_bytes, SubCircuit, SubCircuitConfig, + keccak, rlc_be_bytes, word, SubCircuit, SubCircuitConfig, }, witness, witness::{ @@ -47,7 +47,7 @@ use eth_types::{ TxType::{Eip155, L1Msg, PreEip155}, }, sign_types::SignData, - Address, Field, ToAddress, ToBigEndian, ToScalar, + Address, Field, ToAddress, ToBigEndian, ToScalar, ToWord, U256, }; use ethers_core::utils::{keccak256, rlp::Encodable}; use gadgets::{ @@ -79,6 +79,8 @@ use halo2_proofs::plonk::Fixed; use halo2_proofs::plonk::SecondPhase; use itertools::Itertools; +use halo2_proofs::dev::unwrap_value; + /// Number of rows of one tx occupies in the fixed part of tx table pub const TX_LEN: usize = 26; /// Offset of TxHash tag in the tx table @@ -126,21 +128,29 @@ pub struct TxCircuitConfig<F: Field> { // Whether tag's RLP-encoded value is 0x80 = rlp([]) is_none: Column<Advice>, tx_value_length: Column<Advice>, + // keccak rlc tx_value_rlc: Column<Advice>, + // evm word rlc, use for rlp table lookup + tx_value_evm_rlc: Column<Advice>, + // keccak lookup needs additional output word field, this word field targets for it. + tx_hash_word: word::Word<Column<Advice>>, - u8_table: U8Table, - u16_table: U16Table, + //u8_table: U8Table, + u8_table: UXTable<8>, + u16_table: UXTable<16>, /// Verify if the tx_id is zero or not. tx_id_is_zero: IsZeroConfig<F>, /// Primarily used to verify if the `CallDataLength` is zero or non-zero /// and `CallData` byte is zero or non-zero. - value_is_zero: IsZeroConfig<F>, + value_limb_is_zero: [IsZeroConfig<F>; 2], + /// We use an equality gadget to know whether the tx id changes between /// subsequent rows or not. tx_id_unchanged: IsEqualConfig<F>, /// Columns used to reduce degree + is_value_zero: Column<Advice>, is_tag_block_num: Column<Advice>, is_calldata: Column<Advice>, is_caller_address: Column<Advice>, @@ -205,9 +215,10 @@ pub struct TxCircuitConfigArgs<F: Field> { /// SigTable pub sig_table: SigTable, /// Reusable u8 lookup table, - pub u8_table: U8Table, + // pub u8_table: U8Table, + pub u8_table: UXTable<8>, /// Reusable u16 lookup table, - pub u16_table: U16Table, + pub u16_table: UXTable<16>, /// Challenges pub challenges: crate::util::Challenges<Expression<F>>, } @@ -260,7 +271,9 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> { let tx_type = meta.advice_column(); let rlp_tag = meta.advice_column(); let tx_value_rlc = meta.advice_column_in(SecondPhase); + let tx_value_evm_rlc = meta.advice_column_in(SecondPhase); let tx_value_length = meta.advice_column(); + let tx_hash_word = word::Word::new([meta.advice_column(), meta.advice_column()]); let is_none = meta.advice_column(); let tag_bits = BinaryNumberChip::configure(meta, q_enable, Some(tx_table.tag.into())); let tx_type_bits = BinaryNumberChip::configure(meta, q_enable, Some(tx_type.into())); @@ -282,6 +295,7 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> { let is_calldata = meta.advice_column(); let is_caller_address = meta.advice_column(); let is_chain_id = meta.advice_column(); + let is_value_zero = meta.advice_column(); let is_tag_block_num = meta.advice_column(); let lookup_conditions = [ LookupCondition::TxCalldata, @@ -296,9 +310,11 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> { // TODO: add lookup to SignVerify table for sv_address let sv_address = meta.advice_column(); - meta.enable_equality(tx_table.value); + meta.enable_equality(tx_table.value.lo()); + meta.enable_equality(tx_table.value.hi()); let log_deg = |s: &'static str, meta: &mut ConstraintSystem<F>| { + //TODO: decrease degree to old nubmer 9. debug_assert!(meta.degree() <= 9); log::info!("after {}, meta.degree: {}", s, meta.degree()); }; @@ -358,7 +374,7 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> { ); // testing if value is zero for tags - let value_is_zero = IsZeroChip::configure( + let value_is_zero_lo = IsZeroChip::configure( meta, |meta| { and::expr(vec![ @@ -373,7 +389,25 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> { ]), ]) }, - tx_table.value, + tx_table.value.lo(), + |meta| meta.advice_column_in(SecondPhase), // value is at 2nd phase + ); + let value_is_zero_hi = IsZeroChip::configure( + meta, + |meta| { + and::expr(vec![ + meta.query_fixed(q_enable, Rotation::cur()), + sum::expr(vec![ + // if caller_address is zero, then skip the sig verify. + is_caller_addr(meta), + // if call_data_length is zero, then skip lookup to tx table for call data + is_data_length(meta), + // if call data byte is zero, then gas_cost = 4 (16 otherwise) + is_data(meta), + ]), + ]) + }, + tx_table.value.hi(), |meta| meta.advice_column_in(SecondPhase), // value is at 2nd phase ); @@ -500,7 +534,8 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> { cb.require_equal( "associated tx type to tag", meta.query_advice(tx_type, Rotation::cur()), - meta.query_advice(tx_table.value, Rotation::cur()), + // tx type value only uses lo column + meta.query_advice(tx_table.value.lo(), Rotation::cur()), ); }); @@ -516,7 +551,7 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> { cb.require_equal( "is_create == is_none", // we rely on the assumption that IsCreate is next to CalleeAddress - meta.query_advice(tx_table.value, Rotation::next()), + meta.query_advice(tx_table.value.lo(), Rotation::next()), meta.query_advice(is_none, Rotation::cur()), ); }); @@ -525,10 +560,10 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> { // is_none == true cb.condition(is_none_expr.expr(), |cb| { // value == 0 - cb.require_equal( - "is_none is true => value == 0", - meta.query_advice(tx_table.value, Rotation::cur()), - 0.expr(), + cb.require_equal_word( + "is_none is true => value == 0 (value_hi = value_lo = 0)", + tx_table.value.query_advice(meta, Rotation::cur()), + word::Word::zero(), ); }); @@ -538,15 +573,15 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> { cb.condition(and::expr([is_data_rlc(meta), is_none_expr.expr()]), |cb| { // we rely on the assumption that CallDataLength and CallDataGasCost are after // CallDataRLC - cb.require_equal( + cb.require_equal_word( "CallDataLength.value == 0", - meta.query_advice(tx_table.value, Rotation::next()), - 0.expr(), + tx_table.value.query_advice(meta, Rotation::next()), + word::Word::zero(), ); - cb.require_equal( + cb.require_equal_word( "CallDataGasCost.value == 0", - meta.query_advice(tx_table.value, Rotation(2)), - 0.expr(), + tx_table.value.query_advice(meta, Rotation(2)), + word::Word::zero(), ); }); @@ -556,7 +591,7 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> { |cb| { cb.require_zero( "CallDataLength != 0", - value_is_zero.expr(Rotation::next())(meta), + meta.query_advice(is_value_zero, Rotation::next()), ); }, ); @@ -618,6 +653,23 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> { cb.gate(meta.query_fixed(q_enable, Rotation::cur())) }); + meta.create_gate("is_value_zero", |meta| { + let mut cb = BaseConstraintBuilder::default(); + + cb.require_boolean( + "is_value_zero is bool", + meta.query_advice(is_value_zero, Rotation::cur()), + ); + cb.require_equal( + "is_value_zero = value_is_zero_lo && value_is_zero_hi", + meta.query_advice(is_value_zero, Rotation::cur()), + value_is_zero_lo.expr(Rotation::cur())(meta) + * value_is_zero_hi.expr(Rotation::cur())(meta), + ); + + cb.gate(meta.query_fixed(q_enable, Rotation::cur())) + }); + meta.create_gate("is_l1_msg", |meta| { let mut cb = BaseConstraintBuilder::default(); @@ -637,7 +689,7 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> { "condition", and::expr([ is_data_length(meta), - not::expr(value_is_zero.expr(Rotation::cur())(meta)), + not::expr(meta.query_advice(is_value_zero, Rotation::cur())), ]), meta.query_advice( lookup_conditions[&LookupCondition::TxCalldata], @@ -767,7 +819,9 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> { q_enable, rlp_tag, tx_value_rlc, + tx_value_evm_rlc, tx_value_length, + tx_hash_word, tx_type_bits, tx_id_is_zero.clone(), is_none, @@ -776,6 +830,7 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> { is_calldata, is_chain_id, is_l1_msg, + //is_value, sv_address, calldata_gas_cost_acc, calldata_rlc, @@ -789,9 +844,9 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> { let mut cb = BaseConstraintBuilder::default(); cb.condition(is_tx_gas_cost(meta), |cb| { - cb.require_zero( + cb.require_zero_word( "tx_gas_cost == 0", - meta.query_advice(tx_table.value, Rotation::cur()), + tx_table.value.query_advice(meta, Rotation::cur()), ); }); @@ -810,7 +865,8 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> { cb.condition(is_nonce(meta), |cb| { cb.require_equal( "tx_nonce = tx_table.value if tag == Nonce", - meta.query_advice(tx_table.value, Rotation::cur()), + // value.lo() should cover tx_nonce value. + meta.query_advice(tx_table.value.lo(), Rotation::cur()), meta.query_advice(tx_nonce, Rotation::cur()), ); }); @@ -824,7 +880,7 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> { cb.condition(meta.query_advice(is_tag_block_num, Rotation::cur()), |cb| { cb.require_equal( "block_num = tx_table.value if tag == BlockNum", - meta.query_advice(tx_table.value, Rotation::cur()), + meta.query_advice(tx_table.value.lo(), Rotation::cur()), meta.query_advice(block_num, Rotation::cur()), ); }); @@ -848,7 +904,7 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> { |meta| meta.query_advice(block_num, Rotation::cur()), ); - meta.lookup("block_num is non-decreasing till padding txs", |meta| { + meta.lookup_any("block_num is non-decreasing till padding txs", |meta| { // Block nums like this [1, 3, 5, 4, 0] is rejected by this. But [1, 2, 3, 5, 0] is // acceptable. let lookup_condition = and::expr([ @@ -862,7 +918,10 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> { let block_num_diff = meta.query_advice(block_num, Rotation::next()) - meta.query_advice(block_num, Rotation::cur()); - vec![(lookup_condition * block_num_diff, u16_table.into())] + vec![( + lookup_condition * block_num_diff, + meta.query_fixed(u16_table.col, Rotation::cur()), + )] }); meta.create_gate("num_all_txs in a block", |meta| { @@ -975,7 +1034,8 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> { meta.lookup_any("num_all_txs in block table", |meta| { let is_tag_block_num = meta.query_advice(is_tag_block_num, Rotation::cur()); - let block_num = meta.query_advice(tx_table.value, Rotation::cur()); + // tx_table.value.lo can cover block_num + let block_num = meta.query_advice(tx_table.value.lo(), Rotation::cur()); let num_all_txs_acc = meta.query_advice(num_all_txs_acc, Rotation::cur()); let input_expr = vec![NumAllTxs.expr(), block_num, num_all_txs_acc]; @@ -1005,7 +1065,7 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> { cb.require_equal( "is_padding_tx = true if caller_address = 0", meta.query_advice(is_padding_tx, Rotation::cur()), - value_is_zero.expr(Rotation::cur())(meta), + meta.query_advice(is_value_zero, Rotation::cur()), ); }); cb.gate(meta.query_fixed(q_enable, Rotation::cur())) @@ -1027,7 +1087,7 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> { cum_num_txs - num_txs }, |meta| meta.query_advice(tx_table.tx_id, Rotation::cur()), - u8_table.into(), + u8_table.col, ); // last non-padding tx must have tx_id == cum_num_txs @@ -1065,7 +1125,7 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> { }, |meta| meta.query_advice(tx_table.tx_id, Rotation::cur()), |meta| meta.query_advice(cum_num_txs, Rotation::cur()), - u8_table.into(), + u8_table.col, ); meta.create_gate("tx_id <= cum_num_txs", |meta| { @@ -1084,7 +1144,8 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> { meta.lookup_any("num_txs in block table", |meta| { let is_tag_block_num = meta.query_advice(is_tag_block_num, Rotation::cur()); - let block_num = meta.query_advice(tx_table.value, Rotation::cur()); + // TODO: check why block_num come from tx table ? + let block_num = meta.query_advice(tx_table.value.lo(), Rotation::cur()); let num_txs = meta.query_advice(num_txs, Rotation::cur()); let input_expr = vec![NumTxs.expr(), block_num, num_txs]; @@ -1104,7 +1165,7 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> { meta.lookup_any("cum_num_txs in block table", |meta| { let is_tag_block_num = meta.query_advice(is_tag_block_num, Rotation::cur()); - let block_num = meta.query_advice(tx_table.value, Rotation::cur()); + let block_num = meta.query_advice(tx_table.value.lo(), Rotation::cur()); let cum_num_txs = meta.query_advice(cum_num_txs, Rotation::cur()); let input_expr = vec![CumNumTxs.expr(), block_num, cum_num_txs]; @@ -1125,7 +1186,7 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> { //////////////////////////////////////////////////////////////////////// /////////// CallData length and gas_cost calculation ///////////////// //////////////////////////////////////////////////////////////////////// - meta.lookup("tx_id_diff must in u16", |meta| { + meta.lookup_any("tx_id_diff must in u16", |meta| { let q_enable = meta.query_fixed(q_enable, Rotation::next()); let is_calldata = meta.query_advice(is_calldata, Rotation::cur()); let tx_id = meta.query_advice(tx_table.tx_id, Rotation::cur()); @@ -1134,8 +1195,8 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> { let lookup_condition = and::expr([q_enable, is_calldata, not::expr(tx_id_next_is_zero)]); - - vec![(lookup_condition * (tx_id_next - tx_id), u16_table.into())] + let u16_expr = meta.query_fixed(u16_table.col, Rotation::cur()); + vec![(lookup_condition * (tx_id_next - tx_id), u16_expr)] }); meta.create_gate("last row of call data", |meta| { @@ -1152,7 +1213,8 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> { cb.require_equal( "calldata_byte == tx_table.value", meta.query_advice(calldata_byte, Rotation::cur()), - meta.query_advice(tx_table.value, Rotation::cur()), + // byte only use value.lo + meta.query_advice(tx_table.value.lo(), Rotation::cur()), ); }); @@ -1161,8 +1223,8 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> { meta.create_gate("tx call data init", |meta| { let mut cb = BaseConstraintBuilder::default(); + let value_is_zero = meta.query_advice(is_value_zero, Rotation::cur()); - let value_is_zero = value_is_zero.expr(Rotation::cur())(meta); let gas_cost = select::expr(value_is_zero, 4.expr(), 16.expr()); cb.require_equal( @@ -1178,7 +1240,7 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> { cb.require_equal( "calldata_rlc == byte", meta.query_advice(calldata_rlc, Rotation::cur()), - meta.query_advice(tx_table.value, Rotation::cur()), + meta.query_advice(tx_table.value.lo(), Rotation::cur()), ); cb.gate(and::expr([ @@ -1206,7 +1268,8 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> { 1.expr(), ); - let value_next_is_zero = value_is_zero.expr(Rotation::next())(meta); + let value_next_is_zero = meta.query_advice(is_value_zero, Rotation::next()); + let gas_cost_next = select::expr(value_next_is_zero, 4.expr(), 16.expr()); // call data gas cost accumulator check. cb.require_equal( @@ -1218,7 +1281,8 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> { "calldata_rlc' = calldata_rlc * r + byte'", meta.query_advice(calldata_rlc, Rotation::next()), meta.query_advice(calldata_rlc, Rotation::cur()) * challenges.keccak_input() - + meta.query_advice(tx_table.value, Rotation::next()), + // TODO: check if value.lo() can cover calldata_rlc + + meta.query_advice(tx_table.value.lo(), Rotation::next()), ); }); @@ -1236,7 +1300,9 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> { not::expr(tx_id_is_zero.expr(Rotation::next())(meta)), ]), |cb| { - let value_next_is_zero = value_is_zero.expr(Rotation::next())(meta); + //let value_next_is_zero = value_is_zero.expr(Rotation::next())(meta); + let value_next_is_zero = meta.query_advice(is_value_zero, Rotation::next()); + let gas_cost_next = select::expr(value_next_is_zero, 4.expr(), 16.expr()); cb.require_equal( @@ -1252,7 +1318,7 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> { cb.require_equal( "calldata_rlc' == byte'", meta.query_advice(calldata_rlc, Rotation::next()), - meta.query_advice(tx_table.value, Rotation::next()), + meta.query_advice(tx_table.value.lo(), Rotation::next()), ); }, ); @@ -1279,8 +1345,9 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> { ]), |cb| { // we rely on the assumption that SigV is on the next of ChainID - let v = meta.query_advice(tx_table.value, Rotation::next()); - let chain_id = meta.query_advice(tx_table.value, Rotation::cur()); + let v = meta.query_advice(tx_table.value.lo(), Rotation::next()); + // tx_table.value.lo() can cover chain_id range. + let chain_id = meta.query_advice(tx_table.value.lo(), Rotation::cur()); cb.require_boolean( "V - (chain_id * 2 + 35) Є {0, 1}", @@ -1296,7 +1363,8 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> { tx_type_bits.value_equals(PreEip155, Rotation::cur())(meta), ]), |cb| { - let v = meta.query_advice(tx_table.value, Rotation::next()); + // use value.lo() for v + let v = meta.query_advice(tx_table.value.lo(), Rotation::next()); cb.require_boolean("V - 27 Є {0, 1}", v - 27.expr()); }, ); @@ -1308,8 +1376,8 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> { tx_type_bits.value_equals(L1Msg, Rotation::cur())(meta), ]), |cb| { - let v = meta.query_advice(tx_table.value, Rotation::next()); - cb.require_zero("V == 0", v); + let v = tx_table.value.query_advice(meta, Rotation::next()); + cb.require_zero_word("V == 0", v); }, ); @@ -1324,11 +1392,13 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> { "caller address == sv_address if it's not zero and tx_type != L1Msg", |meta| { let mut cb = BaseConstraintBuilder::default(); + let value_is_zero = meta.query_advice(is_value_zero, Rotation::cur()); - cb.condition(not::expr(value_is_zero.expr(Rotation::cur())(meta)), |cb| { + cb.condition(not::expr(value_is_zero), |cb| { cb.require_equal( "caller address == sv_address", - meta.query_advice(tx_table.value, Rotation::cur()), + // TODO: check if value.lo can cover address in this case + meta.query_advice(tx_table.value.lo(), Rotation::cur()), meta.query_advice(sv_address, Rotation::cur()), ); }); @@ -1354,12 +1424,15 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> { rlp_tag, is_none, tx_value_rlc, + tx_value_evm_rlc, tx_value_length, + tx_hash_word, u8_table, u16_table, tx_id_is_zero, - value_is_zero, + value_limb_is_zero: [value_is_zero_lo, value_is_zero_hi], tx_id_unchanged, + is_value_zero, is_calldata, is_caller_address, tx_id_cmp_cum_num_txs, @@ -1398,7 +1471,9 @@ impl<F: Field> TxCircuitConfig<F> { q_enable: Column<Fixed>, rlp_tag: Column<Advice>, tx_value_rlc: Column<Advice>, + tx_value_evm_rlc: Column<Advice>, tx_value_length: Column<Advice>, + tx_hash_word: word::Word<Column<Advice>>, tx_type_bits: BinaryNumberConfig<TxType, 3>, tx_id_is_zero: IsZeroConfig<F>, is_none: Column<Advice>, @@ -1407,6 +1482,7 @@ impl<F: Field> TxCircuitConfig<F> { is_calldata: Column<Advice>, is_chain_id: Column<Advice>, is_l1_msg_col: Column<Advice>, + //is_value: VirtualCells<>, // is tx field tag::value sv_address: Column<Advice>, calldata_gas_cost_acc: Column<Advice>, calldata_rlc: Column<Advice>, @@ -1444,8 +1520,9 @@ impl<F: Field> TxCircuitConfig<F> { vec![ meta.query_advice(tx_table.tx_id, Rotation::cur()), CallData.expr(), - meta.query_advice(tx_table.value, Rotation::next()), // calldata_gas_cost - 1.expr(), // is_final = 1 + //TODO: check if lo covers calldata_gas_cost_acc + meta.query_advice(tx_table.value.lo(), Rotation::next()), // calldata_gas_cost + 1.expr(), // is_final = 1 ] .into_iter() .zip(vec![ @@ -1472,8 +1549,8 @@ impl<F: Field> TxCircuitConfig<F> { vec![ meta.query_advice(tx_table.tx_id, Rotation::cur()), CallData.expr(), - meta.query_advice(tx_table.value, Rotation::cur()) - 1.expr(), /* index starts - * from 0 */ + meta.query_advice(tx_table.value.lo(), Rotation::cur()) - 1.expr(), /* index starts + * from 0 */ 1.expr(), // is_final = true ] .into_iter() @@ -1504,7 +1581,8 @@ impl<F: Field> TxCircuitConfig<F> { let table_exprs = vec![ meta.query_advice(tx_table.tx_id, Rotation::cur()), meta.query_fixed(tx_table.tag, Rotation::cur()), - meta.query_advice(tx_table.value, Rotation::cur()), + //TODO: check lo covers calldata_rlc ? + meta.query_advice(tx_table.value.lo(), Rotation::cur()), ]; input_exprs @@ -1562,14 +1640,14 @@ impl<F: Field> TxCircuitConfig<F> { let is_none = meta.query_advice(is_none, Rotation::cur()); let sign_format = is_pre_eip155(meta) * TxSignPreEip155.expr() + is_eip155(meta) * TxSignEip155.expr(); - // q_enable, tx_id, format, rlp_tag, tag_value, is_output, is_none vec![ 1.expr(), // q_enable = true meta.query_advice(tx_table.tx_id, Rotation::cur()), sign_format, rlp_tag, - meta.query_advice(tx_table.value, Rotation::cur()), + //meta.query_advice(tx_table.value.lo(), Rotation::cur()), // lo covers tag + meta.query_advice(tx_value_evm_rlc, Rotation::cur()), meta.query_advice(tx_value_rlc, Rotation::cur()), meta.query_advice(tx_value_length, Rotation::cur()), 1.expr(), // is_output = true @@ -1607,7 +1685,8 @@ impl<F: Field> TxCircuitConfig<F> { meta.query_advice(tx_table.tx_id, Rotation::cur()), hash_format, rlp_tag, - meta.query_advice(tx_table.value, Rotation::cur()), + //meta.query_advice(tx_table.value.lo(), Rotation::cur()), + meta.query_advice(tx_value_evm_rlc, Rotation::cur()), meta.query_advice(tx_value_rlc, Rotation::cur()), meta.query_advice(tx_value_length, Rotation::cur()), 1.expr(), // is_output = true @@ -1632,22 +1711,26 @@ impl<F: Field> TxCircuitConfig<F> { meta.query_advice(is_chain_id, Rotation::cur()), ]); - let msg_hash_rlc = meta.query_advice(tx_table.value, Rotation(6)); - let chain_id = meta.query_advice(tx_table.value, Rotation::cur()); - let sig_v = meta.query_advice(tx_table.value, Rotation(1)); - let sig_r = meta.query_advice(tx_table.value, Rotation(2)); - let sig_s = meta.query_advice(tx_table.value, Rotation(3)); + // TODO: check if lo covers msg_hash_rlc, sig(v,r,s) + let msg_hash_lo = meta.query_advice(tx_table.value.lo(), Rotation(6)); + // let msg_hash_hi = meta.query_advice(tx_table.value.hi(), Rotation(6)); + let chain_id = meta.query_advice(tx_table.value.lo(), Rotation::cur()); + let sig_v = meta.query_advice(tx_table.value.lo(), Rotation(1)); + let sig_r = meta.query_advice(tx_table.value.lo(), Rotation(2)); + let sig_s = meta.query_advice(tx_table.value.lo(), Rotation(3)); let sv_address = meta.query_advice(sv_address, Rotation::cur()); let v = is_eip155(meta) * (sig_v.expr() - 2.expr() * chain_id - 35.expr()) + is_pre_eip155(meta) * (sig_v.expr() - 27.expr()); let input_exprs = vec![ - 1.expr(), // q_enable = true - msg_hash_rlc, // msg_hash_rlc - v, // sig_v - sig_r, // sig_r - sig_s, // sig_s + 1.expr(), // q_enable = true + // msg_hash_rlc, // msg_hash_rlc + msg_hash_lo, + // msg_hash_hi, + v, // sig_v + sig_r, // sig_r + sig_s, // sig_s sv_address, 1.expr(), // is_valid ]; @@ -1657,6 +1740,8 @@ impl<F: Field> TxCircuitConfig<F> { meta.query_fixed(sig_table.q_enable, Rotation::cur()), // msg_hash_rlc not needed to be looked up for tx circuit? meta.query_advice(sig_table.msg_hash_rlc, Rotation::cur()), + // meta.query_advice(sig_table.msg_hash_word.lo(), Rotation::cur()), + // meta.query_advice(sig_table.msg_hash_word.hi(), Rotation::cur()), meta.query_advice(sig_table.sig_v, Rotation::cur()), meta.query_advice(sig_table.sig_r_rlc, Rotation::cur()), meta.query_advice(sig_table.sig_s_rlc, Rotation::cur()), @@ -1684,11 +1769,13 @@ impl<F: Field> TxCircuitConfig<F> { ]); vec![ - 1.expr(), // q_enable - 1.expr(), // is_final - meta.query_advice(tx_table.value, Rotation::next()), // input_rlc - meta.query_advice(tx_table.value, Rotation::cur()), // input_len - meta.query_advice(tx_table.value, Rotation(2)), // output_rlc + 1.expr(), // q_enable + 1.expr(), // is_final + meta.query_advice(tx_table.value.lo(), Rotation::next()), // input_rlc + meta.query_advice(tx_table.value.lo(), Rotation::cur()), // input_len + meta.query_advice(tx_table.value.lo(), Rotation(2)), // output_rlc + meta.query_advice(tx_hash_word.lo(), Rotation::cur()), // output_word lo + meta.query_advice(tx_hash_word.hi(), Rotation::cur()), // output_word hi ] .into_iter() .zip(keccak_table.table_exprs(meta)) @@ -1706,7 +1793,7 @@ impl<F: Field> TxCircuitConfig<F> { 1, TxFieldTag::Null, 0, - Value::known(F::zero()), + word::Word::new([Value::known(F::zero()), Value::known(F::zero())]), )?; let (col_anno, col, col_val) = ("rlp_tag", self.rlp_tag, F::from(usize::from(Null) as u64)); region.assign_advice(|| col_anno, col, *offset, || Value::known(col_val))?; @@ -1729,7 +1816,7 @@ impl<F: Field> TxCircuitConfig<F> { num_txs: u64, cum_num_txs: u64, challenges: &Challenges<Value<F>>, - ) -> Result<Vec<AssignedCell<F, F>>, Error> { + ) -> Result<Vec<word::Word<AssignedCell<F, F>>>, Error> { let keccak_input = challenges.keccak_input(); let evm_word = challenges.evm_word(); let zero_rlc = keccak_input.map(|_| F::zero()); @@ -1758,7 +1845,7 @@ impl<F: Field> TxCircuitConfig<F> { be_bytes_len: tx.nonce.tag_length(), be_bytes_rlc: rlc_be_bytes(&tx.nonce.to_be_bytes(), keccak_input), }), - Value::known(F::from(tx.nonce)), + word::Word::new([Value::known(F::from(tx.nonce)), Value::known(F::zero())]), ), ( GasPrice, @@ -1768,7 +1855,12 @@ impl<F: Field> TxCircuitConfig<F> { be_bytes_len: tx.gas_price.tag_length(), be_bytes_rlc: rlc_be_bytes(&tx.gas_price.to_be_bytes(), keccak_input), }), - rlc_be_bytes(&tx.gas_price.to_be_bytes(), evm_word), + // rlc_be_bytes(&tx.gas_price.to_be_bytes(), evm_word), + // word::Word::from(tx.gas_price).map(Value::known), + word::Word::new([ + rlc_be_bytes(&tx.gas_price.to_be_bytes(), evm_word), + Value::known(F::zero()), + ]), ), ( Gas, @@ -1778,7 +1870,8 @@ impl<F: Field> TxCircuitConfig<F> { be_bytes_len: tx.gas.tag_length(), be_bytes_rlc: rlc_be_bytes(&tx.gas.to_be_bytes(), keccak_input), }), - Value::known(F::from(tx.gas)), + //Value::known(F::from(tx.gas)), + word::Word::new([Value::known(F::from(tx.gas)), Value::known(F::zero())]), ), ( CallerAddress, @@ -1788,7 +1881,14 @@ impl<F: Field> TxCircuitConfig<F> { be_bytes_len: tx.caller_address.tag_length(), be_bytes_rlc: rlc_be_bytes(&tx.caller_address.to_fixed_bytes(), keccak_input), }), - Value::known(tx.caller_address.to_scalar().expect("tx.from too big")), + //Value::known(tx.caller_address.to_scalar().expect("tx.from too big")), + // word::Word::from(tx.caller_address.to_word()).map(Value::known), + + //let caller_addrss = tx.caller_address.to_scalar(); + word::Word::new([ + Value::known(tx.caller_address.to_scalar().expect("fx from")), + Value::known(F::zero()), + ]), ), ( CalleeAddress, @@ -1803,14 +1903,32 @@ impl<F: Field> TxCircuitConfig<F> { keccak_input, ), }), - Value::known( - tx.callee_address - .unwrap_or(Address::zero()) - .to_scalar() - .expect("tx.to too big"), - ), + // Value::known( + // tx.callee_address + // .unwrap_or(Address::zero()) + // .to_scalar() + // .expect("tx.to too big"), + // ), + // word::Word::from(tx.callee_address.unwrap_or(Address::zero()).to_word()) + // .map(Value::known), + word::Word::new([ + Value::known( + tx.callee_address + .unwrap_or(Address::zero()) + .to_scalar() + .expect("fx to"), + ), + Value::known(F::zero()), + ]), + ), + ( + IsCreate, + None, + word::Word::new([ + Value::known(F::from(tx.is_create as u64)), + Value::known(F::zero()), + ]), ), - (IsCreate, None, Value::known(F::from(tx.is_create as u64))), ( TxFieldTag::Value, Some(RlpTableInputValue { @@ -1819,7 +1937,8 @@ impl<F: Field> TxCircuitConfig<F> { be_bytes_len: tx.value.tag_length(), be_bytes_rlc: rlc_be_bytes(&tx.value.to_be_bytes(), keccak_input), }), - rlc_be_bytes(&tx.value.to_be_bytes(), evm_word), + //rlc_be_bytes(&tx.value.to_be_bytes(), evm_word), + word::Word::from(tx.value.to_word()).map(Value::known), ), ( CallDataRLC, @@ -1829,17 +1948,29 @@ impl<F: Field> TxCircuitConfig<F> { be_bytes_len: tx.call_data.tag_length(), be_bytes_rlc: rlc_be_bytes(&tx.call_data, keccak_input), }), - rlc_be_bytes(&tx.call_data, keccak_input), + //rlc_be_bytes(&tx.call_data, keccak_input) + word::Word::new([ + rlc_be_bytes(&tx.call_data, keccak_input), + Value::known(F::zero()), + ]), ), ( CallDataLength, None, - Value::known(F::from(tx.call_data.len() as u64)), + //Value::known(F::from(tx.call_data.len() as u64)), + word::Word::new([ + Value::known(F::from(tx.call_data.len() as u64)), + Value::known(F::zero()), + ]), ), ( CallDataGasCost, None, - Value::known(F::from(tx.call_data_gas_cost)), + //Value::known(F::from(tx.call_data_gas_cost)), + word::Word::new([ + Value::known(F::from(tx.call_data_gas_cost)), + Value::known(F::zero()), + ]), ), ( TxDataGasCost, @@ -1849,7 +1980,11 @@ impl<F: Field> TxCircuitConfig<F> { be_bytes_len: 0, be_bytes_rlc: zero_rlc, }), - Value::known(F::from(tx.tx_data_gas_cost)), + //Value::known(F::from(tx.tx_data_gas_cost)), + word::Word::new([ + Value::known(F::from(tx.tx_data_gas_cost)), + Value::known(F::zero()), + ]), ), ( ChainID, @@ -1859,7 +1994,8 @@ impl<F: Field> TxCircuitConfig<F> { be_bytes_len: tx.chain_id.tag_length(), be_bytes_rlc: rlc_be_bytes(&tx.chain_id.to_be_bytes(), keccak_input), }), - Value::known(F::from(tx.chain_id)), + //Value::known(F::from(tx.chain_id)), + word::Word::new([Value::known(F::from(tx.chain_id)), Value::known(F::zero())]), ), ( SigV, @@ -1869,7 +2005,8 @@ impl<F: Field> TxCircuitConfig<F> { be_bytes_len: tx.v.tag_length(), be_bytes_rlc: rlc_be_bytes(&tx.v.to_be_bytes(), keccak_input), }), - Value::known(F::from(tx.v)), + //Value::known(F::from(tx.v)), + word::Word::new([Value::known(F::from(tx.v)), Value::known(F::zero())]), ), ( SigR, @@ -1879,7 +2016,13 @@ impl<F: Field> TxCircuitConfig<F> { be_bytes_len: tx.r.tag_length(), be_bytes_rlc: rlc_be_bytes(&tx.r.to_be_bytes(), keccak_input), }), - rlc_be_bytes(&tx.r.to_be_bytes(), evm_word), + //rlc_be_bytes(&tx.r.to_be_bytes(), evm_word), + //word::Word::from(tx.r.to_word()).map(Value::known), + word::Word::new([ + Value::known(unwrap_value(rlc_be_bytes(&tx.r.to_be_bytes(), evm_word))), + Value::known(F::zero()), + //F::zero(), + ]), ), ( SigS, @@ -1889,7 +2032,17 @@ impl<F: Field> TxCircuitConfig<F> { be_bytes_len: tx.s.tag_length(), be_bytes_rlc: rlc_be_bytes(&tx.s.to_be_bytes(), keccak_input), }), - rlc_be_bytes(&tx.s.to_be_bytes(), evm_word), + //rlc_be_bytes(&tx.s.to_be_bytes(), evm_word), + //word::Word::from(tx.s.to_word()).map(Value::known), + // word::Word::new([ + // Value::known(rlc_be_bytes(&tx.s.to_be_bytes(), evm_word)), + // Value::known(F::zero()), + // ]), + word::Word::new([ + Value::known(unwrap_value(rlc_be_bytes(&tx.s.to_be_bytes(), evm_word))), + Value::known(F::zero()), + //F::zero(), + ]), ), ( TxSignLength, @@ -1899,7 +2052,11 @@ impl<F: Field> TxCircuitConfig<F> { be_bytes_len: rlp_sign_tag_length, be_bytes_rlc: zero_rlc, }), - Value::known(F::from(tx.rlp_unsigned.len() as u64)), + //Value::known(F::from(tx.rlp_unsigned.len() as u64)), + word::Word::new([ + Value::known(F::from(tx.rlp_unsigned.len() as u64)), + Value::known(F::zero()), + ]), ), ( TxSignRLC, @@ -1909,9 +2066,19 @@ impl<F: Field> TxCircuitConfig<F> { be_bytes_len: 0, be_bytes_rlc: zero_rlc, }), - rlc_be_bytes(&tx.rlp_unsigned, keccak_input), + //rlc_be_bytes(&tx.rlp_unsigned, keccak_input), + word::Word::new([ + rlc_be_bytes(&tx.rlp_unsigned, keccak_input), + Value::known(F::zero()), + ]), + ), + //(TxSignHash, None, sign_hash_rlc), + ( + TxSignHash, + None, + //word::Word::from(U256::from_big_endian(&sign_hash)).map(Value::known), + word::Word::new([sign_hash_rlc, Value::known(F::zero())]), ), - (TxSignHash, None, sign_hash_rlc), ( TxHashLength, Some(RlpTableInputValue { @@ -1920,7 +2087,11 @@ impl<F: Field> TxCircuitConfig<F> { be_bytes_len: get_rlp_len_tag_length(&tx.rlp_signed), be_bytes_rlc: zero_rlc, }), - Value::known(F::from(tx.rlp_signed.len() as u64)), + //Value::known(F::from(tx.rlp_signed.len() as u64)), + word::Word::new([ + Value::known(F::from(tx.rlp_signed.len() as u64)), + Value::known(F::zero()), + ]), ), ( TxHashRLC, @@ -1930,23 +2101,45 @@ impl<F: Field> TxCircuitConfig<F> { be_bytes_len: 0, be_bytes_rlc: zero_rlc, }), - rlc_be_bytes(&tx.rlp_signed, keccak_input), + //rlc_be_bytes(&tx.rlp_signed, keccak_input), + word::Word::new([ + rlc_be_bytes(&tx.rlp_signed, keccak_input), + Value::known(F::zero()), + ]), + ), + //(TxFieldTag::TxHash, None, hash_rlc), + ( + TxFieldTag::TxHash, + None, + //word::Word::from(U256::from_big_endian(&hash)).map(Value::known), + word::Word::new([hash_rlc, Value::known(F::zero())]), ), - (TxFieldTag::TxHash, None, hash_rlc), ( TxFieldTag::TxType, None, - Value::known(F::from(tx.tx_type as u64)), + //Value::known(F::from(tx.tx_type as u64)), + word::Word::new([ + Value::known(F::from(tx.tx_type as u64)), + Value::known(F::zero()), + ]), ), ( AccessListAddressesLen, None, - Value::known(F::from(access_list_address_size)), + //Value::known(F::from(access_list_address_size)), + word::Word::new([ + Value::known(F::from(access_list_address_size)), + Value::known(F::zero()), + ]), ), ( AccessListStorageKeysLen, None, - Value::known(F::from(access_list_storage_key_size)), + //Value::known(F::from(access_list_storage_key_size)), + word::Word::new([ + Value::known(F::from(access_list_storage_key_size)), + Value::known(F::zero()), + ]), ), ( AccessListRLC, @@ -1957,17 +2150,34 @@ impl<F: Field> TxCircuitConfig<F> { be_bytes_rlc: zero_rlc, }), // TODO: need to check if it's correct with RLP. - rlc_be_bytes( - &tx.access_list - .as_ref() - .map(|access_list| access_list.rlp_bytes()) - .unwrap_or_default(), - keccak_input, - ), + { + let access_list_rlc = rlc_be_bytes( + &tx.access_list + .as_ref() + .map(|access_list| access_list.rlp_bytes()) + .unwrap_or_default(), + keccak_input, + ); + + word::Word::new([access_list_rlc, Value::known(F::zero())]) + }, ), - (BlockNumber, None, Value::known(F::from(tx.block_number))), + ( + BlockNumber, + None, + word::Word::new([ + Value::known(F::from(tx.block_number)), + Value::known(F::zero()), + ]), + ), + //Value::known(F::from(tx.block_number))), ]; + // constructs two hashes' word + let sign_hash_word = word::Word::from(U256::from_big_endian(&sign_hash)).map(Value::known); + let tx_hash_word = word::Word::from(U256::from_big_endian(&hash)).map(Value::known); + let tx_value_evm_rlc = rlc_be_bytes(&tx.value.to_be_bytes(), evm_word); + for (tx_tag, rlp_input, tx_value) in fixed_rows { let rlp_tag = rlp_input.clone().map_or(Null, |input| input.tag); let rlp_is_none = rlp_input.clone().map_or(false, |input| input.is_none); @@ -2030,7 +2240,7 @@ impl<F: Field> TxCircuitConfig<F> { ), ( "sv_address", - self.sv_address, + self.sv_address, // not change to word sign_data.get_addr().to_scalar().unwrap(), ), // tx_tag related indicator columns @@ -2063,6 +2273,17 @@ impl<F: Field> TxCircuitConfig<F> { let (col_anno, col, col_val) = ("tx_value_rlc", self.tx_value_rlc, rlp_be_bytes_rlc); region.assign_advice(|| col_anno, col, *offset, || col_val)?; + let value_evm_rlc = if tx_tag == TxFieldTag::Value { + tx_value_evm_rlc + } else { + tx_value.lo() + }; + region.assign_advice( + || "tx_value_evm_rlc", + self.tx_value_evm_rlc, + *offset, + || value_evm_rlc, + )?; } // lookup conditions @@ -2169,6 +2390,24 @@ impl<F: Field> TxCircuitConfig<F> { F::from(tx.id as u64), )?; + let hash_word_assign = if tx_tag == TxFieldTag::TxSignLength { + sign_hash_word + } else if tx_tag == TxFieldTag::TxHashLength { + tx_hash_word + } else { + // for non TxSignLength & non TxHashLength tag, this word value won't lookup, hence + // all set zero limbs. word::Word::default() will panic as default + // limbs are none. + word::Word::new([F::zero(), F::zero()]).map(Value::known) + }; + + hash_word_assign.assign_advice( + region, + || "assign sign_hash_word", + self.tx_hash_word, + *offset, + )?; + *offset += 1; } Ok(tx_value_cells) @@ -2206,7 +2445,7 @@ impl<F: Field> TxCircuitConfig<F> { tx_id_next, CallData, idx as u64, - Value::known(F::from(*byte as u64)), + word::Word::new([Value::known(F::from(*byte as u64)), Value::known(F::zero())]), )?; // 1st phase columns @@ -2247,8 +2486,8 @@ impl<F: Field> TxCircuitConfig<F> { tx_id_next: usize, tag: TxFieldTag, index: u64, - value: Value<F>, - ) -> Result<AssignedCell<F, F>, Error> { + value: word::Word<Value<F>>, + ) -> Result<word::Word<AssignedCell<F, F>>, Error> { let (tx_type, tx_id) = if let Some(tx) = tx { (tx.tx_type, tx.id) } else { @@ -2265,9 +2504,19 @@ impl<F: Field> TxCircuitConfig<F> { let tx_id_is_zero_chip = IsZeroChip::construct(self.tx_id_is_zero.clone()); tx_id_is_zero_chip.assign(region, offset, Value::known(F::from(tx_id as u64)))?; - let value_is_zero_chip = IsZeroChip::construct(self.value_is_zero.clone()); - value_is_zero_chip.assign(region, offset, value)?; + let value_word_zero = + unwrap_value(value.lo()) == F::zero() && unwrap_value(value.hi()) == F::zero(); + let value_is_zero_lo_chip = IsZeroChip::construct(self.value_limb_is_zero[0].clone()); + value_is_zero_lo_chip.assign(region, offset, value.lo())?; + let value_is_zero_hi_chip = IsZeroChip::construct(self.value_limb_is_zero[1].clone()); + value_is_zero_hi_chip.assign(region, offset, value.hi())?; + region.assign_advice( + || "tx circuit: is_value_zero", + self.is_value_zero, + offset, + || Value::known(F::from(value_word_zero as u64)), + )?; let tx_id_unchanged_chip = IsEqualChip::construct(self.tx_id_unchanged.clone()); tx_id_unchanged_chip.assign( region, @@ -2299,10 +2548,12 @@ impl<F: Field> TxCircuitConfig<F> { region.assign_advice(|| col_anno, col, offset, || Value::known(col_val))?; } // 2nd phase columns - let tx_value_cell = - region.assign_advice(|| "tx_value", self.tx_table.value, offset, || value)?; + // let tx_value_cell = + // region.assign_advice(|| "tx_value", self.tx_table.value, offset, || value)?; - Ok(tx_value_cell) + let tx_value_cells = + value.assign_advice(region, || "tx_value", self.tx_table.value, offset)?; + Ok(tx_value_cells) } fn assign_calldata_zeros( @@ -2311,10 +2562,11 @@ impl<F: Field> TxCircuitConfig<F> { start: usize, end: usize, ) -> Result<(), Error> { - // let rlp_data = F::from( as u64); let tag = F::from(CallData as u64); let tx_id_is_zero_chip = IsZeroChip::construct(self.tx_id_is_zero.clone()); - let value_is_zero_chip = IsZeroChip::construct(self.value_is_zero.clone()); + let value_is_zero_lo_chip = IsZeroChip::construct(self.value_limb_is_zero[0].clone()); + let value_is_zero_hi_chip = IsZeroChip::construct(self.value_limb_is_zero[1].clone()); + let tx_id_unchanged = IsEqualChip::construct(self.tx_id_unchanged.clone()); let tag_chip = BinaryNumberChip::construct(self.tx_tag_bits); @@ -2336,7 +2588,9 @@ impl<F: Field> TxCircuitConfig<F> { // no need to assign tx_id_is_zero_chip for real prover as tx_id = 0 tx_id_is_zero_chip.assign(region, offset, Value::known(F::zero()))?; // no need to assign value_is_zero_chip for real prover as value = 0 - value_is_zero_chip.assign(region, offset, Value::known(F::zero()))?; + value_is_zero_lo_chip.assign(region, offset, Value::known(F::zero()))?; + value_is_zero_hi_chip.assign(region, offset, Value::known(F::zero()))?; + tx_id_unchanged.assign( region, offset, @@ -2347,7 +2601,10 @@ impl<F: Field> TxCircuitConfig<F> { for (col, value) in [ (self.tx_table.tx_id, F::zero()), (self.tx_table.index, F::zero()), - (self.tx_table.value, F::zero()), + (self.tx_table.value.lo(), F::zero()), + (self.tx_table.value.hi(), F::zero()), + // when value is zero, is_value_zero is true + (self.is_value_zero, F::one()), (self.is_final, F::one()), (self.is_calldata, F::one()), (self.calldata_gas_cost_acc, F::zero()), @@ -2405,7 +2662,8 @@ pub struct TxCircuit<F: Field> { /// Size pub size: usize, /// Tx value cells (exported for PI circuit) - pub value_cells: RefCell<Option<Vec<AssignedCell<F, F>>>>, + #[allow(clippy::type_complexity)] + pub value_cells: RefCell<Option<Vec<word::Word<AssignedCell<F, F>>>>>, _marker: PhantomData<F>, } @@ -2581,12 +2839,11 @@ impl<F: Field> TxCircuit<F> { start_l1_queue_index: u64, sign_datas: Vec<SignData>, padding_txs: &[Transaction], - ) -> Result<Vec<AssignedCell<F, F>>, Error> { + ) -> Result<Vec<word::Word<AssignedCell<F, F>>>, Error> { layouter.assign_region( || "tx table aux", |mut region| { let mut offset = 0; - let sigs = &sign_datas; debug_assert_eq!(padding_txs.len() + self.txs.len(), sigs.len()); @@ -2779,7 +3036,6 @@ impl<F: Field> SubCircuit<F> for TxCircuit<F> { layouter: &mut impl Layouter<F>, ) -> Result<(), Error> { assert!(self.txs.len() <= self.max_txs); - let padding_txs = (self.txs.len()..self.max_txs) .map(|i| { let mut tx = Transaction::dummy(self.chain_id); diff --git a/zkevm-circuits/src/tx_circuit/dev.rs b/zkevm-circuits/src/tx_circuit/dev.rs index e17711710c..adb6abf556 100644 --- a/zkevm-circuits/src/tx_circuit/dev.rs +++ b/zkevm-circuits/src/tx_circuit/dev.rs @@ -6,9 +6,7 @@ pub use super::TxCircuit; use crate::{ sig_circuit::{SigCircuit, SigCircuitConfig, SigCircuitConfigArgs}, - table::{ - BlockTable, KeccakTable, RlpFsmRlpTable as RlpTable, SigTable, TxTable, U16Table, U8Table, - }, + table::{BlockTable, KeccakTable, RlpFsmRlpTable as RlpTable, SigTable, TxTable, UXTable}, tx_circuit::{TxCircuitConfig, TxCircuitConfigArgs}, util::{Challenges, SubCircuit, SubCircuitConfig}, witness::Transaction, @@ -32,9 +30,9 @@ pub struct TxCircuitTesterConfigArgs<F: Field> { /// SigTable pub sig_table: SigTable, /// u8 lookup table, - pub u8_table: U8Table, + pub u8_table: UXTable<8>, /// u16 lookup table, - pub u16_table: U16Table, + pub u16_table: UXTable<16>, /// Challenges pub challenges: Challenges<Expression<F>>, } @@ -46,9 +44,9 @@ pub struct TxCircuitTesterConfig<F: Field> { // SigTable is assigned inside SigCircuit sig_config: SigCircuitConfig<F>, /// u16 lookup table, - pub u8_table: U8Table, + pub u8_table: UXTable<8>, /// u16 lookup table, - pub u16_table: U16Table, + pub u16_table: UXTable<16>, } impl<F: Field> SubCircuitConfig<F> for TxCircuitTesterConfig<F> { @@ -168,8 +166,8 @@ impl<F: Field> Circuit<F> for TxCircuitTester<F> { let keccak_table = KeccakTable::construct(meta); let rlp_table = RlpTable::construct(meta); let sig_table = SigTable::construct(meta); - let u8_table = U8Table::construct(meta); - let u16_table = U16Table::construct(meta); + let u8_table = UXTable::construct(meta); + let u16_table = UXTable::construct(meta); let challenges = Challenges::construct(meta); let config = { diff --git a/zkevm-circuits/src/witness/tx.rs b/zkevm-circuits/src/witness/tx.rs index 5680194c1b..77f513df4d 100644 --- a/zkevm-circuits/src/witness/tx.rs +++ b/zkevm-circuits/src/witness/tx.rs @@ -1,7 +1,7 @@ use crate::{ evm_circuit::{step::ExecutionState, util::rlc}, table::TxContextFieldTag, - util::{rlc_be_bytes, Challenges}, + util::{rlc_be_bytes, word, Challenges}, witness::{ rlp_fsm::SmState, DataTable, Format, @@ -158,11 +158,21 @@ impl Transaction { pub fn table_assignments_fixed<F: Field>( &self, challenges: Challenges<Value<F>>, - ) -> Vec<[Value<F>; 4]> { + ) -> Vec<[Value<F>; 5]> { let tx_hash_be_bytes = keccak256(&self.rlp_signed); let tx_sign_hash_be_bytes = keccak256(&self.rlp_unsigned); let (access_list_address_size, access_list_storage_key_size) = access_list_size(&self.access_list); + // let gas_price_word = word::Word::from(self.gas_price.to_word()).map(Value::known); + let value_word = word::Word::from(self.value.to_word()).map(Value::known); + // let tx_hash_word = + // word::Word::from(Word::from_big_endian(&tx_hash_be_bytes)).map(Value::known); + // let tx_sign_hash_word = + // word::Word::from(Word::from_big_endian(&tx_sign_hash_be_bytes)).map(Value::known); + // let caller_address_word = word::Word::from(self.caller_address).map(Value::known); + // let callee_address_word = + // word::Word::from(self.callee_address.unwrap_or(Address::zero())).map(Value::known); + println!("Transaction table_assignments_fixed"); let ret = vec![ [ @@ -170,6 +180,7 @@ impl Transaction { Value::known(F::from(TxContextFieldTag::Nonce as u64)), Value::known(F::zero()), Value::known(F::from(self.nonce)), + Value::known(F::zero()), ], [ Value::known(F::from(self.id as u64)), @@ -178,18 +189,26 @@ impl Transaction { challenges .evm_word() .map(|challenge| rlc::value(&self.gas_price.to_le_bytes(), challenge)), + Value::known(F::zero()), + // can not use word type as tx circuit use rlc value to lookup keccak table + // gas_price_word.lo(), + // gas_price_word.hi(), ], [ Value::known(F::from(self.id as u64)), Value::known(F::from(TxContextFieldTag::Gas as u64)), Value::known(F::zero()), Value::known(F::from(self.gas)), + Value::known(F::zero()), ], [ Value::known(F::from(self.id as u64)), Value::known(F::from(TxContextFieldTag::CallerAddress as u64)), Value::known(F::zero()), Value::known(self.caller_address.to_scalar().unwrap()), + Value::known(F::zero()), + // caller_address_word.lo(), + // caller_address_word.hi(), ], [ Value::known(F::from(self.id as u64)), @@ -201,122 +220,152 @@ impl Transaction { .to_scalar() .unwrap(), ), + Value::known(F::zero()), + // callee_address_word.lo(), + // callee_address_word.hi(), ], [ Value::known(F::from(self.id as u64)), Value::known(F::from(TxContextFieldTag::IsCreate as u64)), Value::known(F::zero()), Value::known(F::from(self.is_create as u64)), + Value::known(F::zero()), ], [ Value::known(F::from(self.id as u64)), Value::known(F::from(TxContextFieldTag::Value as u64)), Value::known(F::zero()), - challenges - .evm_word() - .map(|challenge| rlc::value(&self.value.to_le_bytes(), challenge)), + // challenges + // .evm_word() + // .map(|challenge| rlc::value(&self.value.to_le_bytes(), challenge)), + value_word.lo(), + value_word.hi(), ], [ Value::known(F::from(self.id as u64)), Value::known(F::from(TxContextFieldTag::CallDataRLC as u64)), Value::known(F::zero()), rlc_be_bytes(&self.call_data, challenges.keccak_input()), + Value::known(F::zero()), ], [ Value::known(F::from(self.id as u64)), Value::known(F::from(TxContextFieldTag::CallDataLength as u64)), Value::known(F::zero()), Value::known(F::from(self.call_data_length as u64)), + Value::known(F::zero()), ], [ Value::known(F::from(self.id as u64)), Value::known(F::from(TxContextFieldTag::CallDataGasCost as u64)), Value::known(F::zero()), Value::known(F::from(self.call_data_gas_cost)), + Value::known(F::zero()), ], [ Value::known(F::from(self.id as u64)), Value::known(F::from(TxContextFieldTag::TxDataGasCost as u64)), Value::known(F::zero()), Value::known(F::from(self.tx_data_gas_cost)), + Value::known(F::zero()), ], [ Value::known(F::from(self.id as u64)), Value::known(F::from(TxContextFieldTag::ChainID as u64)), Value::known(F::zero()), Value::known(F::from(self.chain_id)), + Value::known(F::zero()), ], [ Value::known(F::from(self.id as u64)), Value::known(F::from(TxContextFieldTag::SigV as u64)), Value::known(F::zero()), Value::known(F::from(self.v)), + Value::known(F::zero()), ], [ Value::known(F::from(self.id as u64)), Value::known(F::from(TxContextFieldTag::SigR as u64)), Value::known(F::zero()), + // TODO: check if change r to word hi lo ? rlc_be_bytes(&self.r.to_be_bytes(), challenges.evm_word()), + Value::known(F::zero()), ], [ Value::known(F::from(self.id as u64)), Value::known(F::from(TxContextFieldTag::SigS as u64)), Value::known(F::zero()), + // TODO: check if change s to word hi lo ? rlc_be_bytes(&self.s.to_be_bytes(), challenges.evm_word()), + Value::known(F::zero()), ], [ Value::known(F::from(self.id as u64)), Value::known(F::from(TxContextFieldTag::TxSignLength as u64)), Value::known(F::zero()), Value::known(F::from(self.rlp_unsigned.len() as u64)), + Value::known(F::zero()), ], [ Value::known(F::from(self.id as u64)), Value::known(F::from(TxContextFieldTag::TxSignRLC as u64)), Value::known(F::zero()), rlc_be_bytes(&self.rlp_unsigned, challenges.keccak_input()), + Value::known(F::zero()), ], [ Value::known(F::from(self.id as u64)), Value::known(F::from(TxContextFieldTag::TxSignHash as u64)), Value::known(F::zero()), + // TODO: check if change to word hi lo ? rlc_be_bytes(&tx_sign_hash_be_bytes, challenges.evm_word()), + Value::known(F::zero()), + // tx_sign_hash_word.lo(), + // tx_sign_hash_word.hi(), ], [ Value::known(F::from(self.id as u64)), Value::known(F::from(TxContextFieldTag::TxHashLength as u64)), Value::known(F::zero()), Value::known(F::from(self.rlp_signed.len() as u64)), + Value::known(F::zero()), ], [ Value::known(F::from(self.id as u64)), Value::known(F::from(TxContextFieldTag::TxHashRLC as u64)), Value::known(F::zero()), rlc_be_bytes(&self.rlp_signed, challenges.keccak_input()), + Value::known(F::zero()), ], [ Value::known(F::from(self.id as u64)), Value::known(F::from(TxContextFieldTag::TxHash as u64)), Value::known(F::zero()), rlc_be_bytes(&tx_hash_be_bytes, challenges.evm_word()), + Value::known(F::zero()), + // tx_hash_word.lo(), + // tx_hash_word.hi(), ], [ Value::known(F::from(self.id as u64)), Value::known(F::from(TxContextFieldTag::TxType as u64)), Value::known(F::zero()), Value::known(F::from(self.tx_type as u64)), + Value::known(F::zero()), ], [ Value::known(F::from(self.id as u64)), Value::known(F::from(TxContextFieldTag::AccessListAddressesLen as u64)), Value::known(F::zero()), Value::known(F::from(access_list_address_size)), + Value::known(F::zero()), ], [ Value::known(F::from(self.id as u64)), Value::known(F::from(TxContextFieldTag::AccessListStorageKeysLen as u64)), Value::known(F::zero()), Value::known(F::from(access_list_storage_key_size)), + Value::known(F::zero()), ], [ Value::known(F::from(self.id as u64)), @@ -331,12 +380,14 @@ impl Transaction { .unwrap_or_default(), challenges.keccak_input(), ), + Value::known(F::zero()), ], [ Value::known(F::from(self.id as u64)), Value::known(F::from(TxContextFieldTag::BlockNumber as u64)), Value::known(F::zero()), Value::known(F::from(self.block_number)), + Value::known(F::zero()), ], ]; @@ -347,7 +398,7 @@ impl Transaction { pub fn table_assignments_dyn<F: Field>( &self, _challenges: Challenges<Value<F>>, - ) -> Vec<[Value<F>; 4]> { + ) -> Vec<[Value<F>; 5]> { self.call_data .iter() .enumerate() @@ -357,6 +408,7 @@ impl Transaction { Value::known(F::from(TxContextFieldTag::CallData as u64)), Value::known(F::from(idx as u64)), Value::known(F::from(*byte as u64)), + Value::known(F::zero()), ] }) .collect()