diff --git a/gadgets/src/comparator.rs b/gadgets/src/comparator.rs index cd39e38c51..407198ca98 100644 --- a/gadgets/src/comparator.rs +++ b/gadgets/src/comparator.rs @@ -5,13 +5,14 @@ use eth_types::Field; use halo2_proofs::{ arithmetic::FieldExt, circuit::{Chip, Region, Value}, - plonk::{ConstraintSystem, Error, Expression, VirtualCells}, + plonk::{ConstraintSystem, Error, Expression, TableColumn, VirtualCells}, poly::Rotation, }; -use crate::{is_equal::IsEqualInstruction, less_than::LtInstruction}; - -use super::{is_equal::IsEqualChip, less_than::LtChip}; +use crate::{ + is_equal::{IsEqualChip, IsEqualInstruction}, + less_than::{LtChip, LtInstruction}, +}; /// Instruction that the Comparator chip needs to implement. pub trait ComparatorInstruction { @@ -61,8 +62,10 @@ impl ComparatorChip { q_enable: impl FnOnce(&mut VirtualCells) -> Expression + Clone, lhs: impl FnOnce(&mut VirtualCells) -> Expression + Clone, rhs: impl FnOnce(&mut VirtualCells) -> Expression + Clone, + u8_table: TableColumn, ) -> ComparatorConfig { - let lt_config = LtChip::configure(meta, q_enable.clone(), lhs.clone(), rhs.clone()); + let lt_config = + LtChip::configure(meta, q_enable.clone(), lhs.clone(), rhs.clone(), u8_table); let eq_config = IsEqualChip::configure(meta, q_enable, lhs, rhs); ComparatorConfig { diff --git a/gadgets/src/less_than.rs b/gadgets/src/less_than.rs index c2b51ce05d..c2613a1fc6 100644 --- a/gadgets/src/less_than.rs +++ b/gadgets/src/less_than.rs @@ -4,15 +4,13 @@ use eth_types::Field; use halo2_proofs::{ arithmetic::FieldExt, circuit::{Chip, Region, Value}, - plonk::{Advice, Column, ConstraintSystem, Error, Expression, VirtualCells}, + plonk::{Advice, Column, ConstraintSystem, Error, Expression, TableColumn, VirtualCells}, poly::Rotation, }; -use crate::util::sum; - -use super::{ +use crate::{ bool_check, - util::{expr_from_bytes, pow_of_two}, + util::{expr_from_bytes, pow_of_two, sum}, }; /// Instruction that the Lt chip needs to implement. @@ -25,6 +23,11 @@ pub trait LtInstruction { lhs: F, rhs: F, ) -> Result<(), Error>; + + #[cfg(test)] + /// Load the u8 lookup table. + fn dev_load(&self, layouter: &mut impl halo2_proofs::circuit::Layouter) + -> Result<(), Error>; } /// Config for the Lt chip. @@ -33,8 +36,9 @@ pub struct LtConfig { /// Denotes the lt outcome. If lhs < rhs then lt == 1, otherwise lt == 0. pub lt: Column, /// Denotes the bytes representation of the difference between lhs and rhs. - /// Note that the range of each byte is not checked by this config. pub diff: [Column; N_BYTES], + /// Denotes the range within which each byte should lie. + pub u8_table: TableColumn, /// Denotes the range within which both lhs and rhs lie. pub range: F, } @@ -62,16 +66,17 @@ impl LtChip { /// Configures the Lt chip. pub fn configure( meta: &mut ConstraintSystem, - q_enable: impl FnOnce(&mut VirtualCells<'_, F>) -> Expression, + q_enable: impl FnOnce(&mut VirtualCells<'_, F>) -> Expression + Clone, lhs: impl FnOnce(&mut VirtualCells) -> Expression, rhs: impl FnOnce(&mut VirtualCells) -> Expression, + u8_table: TableColumn, ) -> LtConfig { let lt = meta.advice_column(); let diff = [(); N_BYTES].map(|_| meta.advice_column()); let range = pow_of_two(N_BYTES * 8); meta.create_gate("lt gate", |meta| { - let q_enable = q_enable(meta); + let q_enable = q_enable.clone()(meta); let lt = meta.query_advice(lt, Rotation::cur()); let diff_bytes = diff @@ -89,7 +94,22 @@ impl LtChip { .map(move |poly| q_enable.clone() * poly) }); - LtConfig { lt, diff, range } + for cell_column in diff { + meta.lookup("range check for u8", |meta| { + let q_enable = q_enable.clone()(meta); + vec![( + q_enable * meta.query_advice(cell_column, Rotation::cur()), + u8_table, + )] + }); + } + + LtConfig { + lt, + diff, + u8_table, + range, + } } /// Constructs a Lt chip given a config. @@ -129,6 +149,29 @@ impl LtInstruction for LtChip { Ok(()) } + + #[cfg(test)] + fn dev_load( + &self, + layouter: &mut impl halo2_proofs::circuit::Layouter, + ) -> Result<(), Error> { + const RANGE: usize = u8::MAX as usize; + + layouter.assign_table( + || "load u8 range check table", + |mut table| { + for i in 0..=RANGE { + table.assign_cell( + || "assign cell in fixed column", + self.config.u8_table, + i, + || Value::known(F::from(i as u64)), + )?; + } + Ok(()) + }, + ) + } } impl Chip for LtChip { @@ -164,7 +207,7 @@ mod test { // TODO: remove zk blinding factors in halo2 to restore the // correct k (without the extra + 2). - let k = usize::BITS - $values.len().leading_zeros() + 2; + let k = (usize::BITS - $values.len().leading_zeros() + 2).max(9); let circuit = TestCircuit:: { values: Some($values), checks: Some($checks), @@ -181,7 +224,7 @@ mod test { // TODO: remove zk blinding factors in halo2 to restore the // correct k (without the extra + 2). - let k = usize::BITS - $values.len().leading_zeros() + 2; + let k = (usize::BITS - $values.len().leading_zeros() + 2).max(9); let circuit = TestCircuit:: { values: Some($values), checks: Some($checks), @@ -222,12 +265,14 @@ 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 lt = LtChip::configure( meta, |meta| meta.query_selector(q_enable), |meta| meta.query_advice(value, Rotation::prev()), |meta| meta.query_advice(value, Rotation::cur()), + u8_table, ); let config = Self::Config { @@ -265,6 +310,8 @@ mod test { let (first_value, values) = values.split_at(1); let first_value = first_value[0]; + chip.dev_load(&mut layouter)?; + layouter.assign_region( || "witness", |mut region| { @@ -340,12 +387,14 @@ 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 lt = LtChip::configure( meta, |meta| meta.query_selector(q_enable), |meta| meta.query_advice(value_a, Rotation::cur()), |meta| meta.query_advice(value_b, Rotation::cur()), + u16_table, ); let config = Self::Config { @@ -387,6 +436,8 @@ mod test { .ok_or(Error::Synthesis)?; let checks = self.checks.as_ref().ok_or(Error::Synthesis)?; + chip.dev_load(&mut layouter)?; + layouter.assign_region( || "witness", |mut region| { diff --git a/zkevm-circuits/src/rlp_circuit_fsm.rs b/zkevm-circuits/src/rlp_circuit_fsm.rs index 3e69709b81..5796a64017 100644 --- a/zkevm-circuits/src/rlp_circuit_fsm.rs +++ b/zkevm-circuits/src/rlp_circuit_fsm.rs @@ -5,9 +5,21 @@ mod dev; #[cfg(any(feature = "test", test))] mod test; -use std::marker::PhantomData; - -use crate::util::is_zero::{IsZeroChip, IsZeroConfig}; +use crate::{ + evm_circuit::util::constraint_builder::{BaseConstraintBuilder, ConstrainBuilderCommon}, + table::{LookupTable, RlpFsmRlpTable, U8Table}, + util::{ + is_zero::{IsZeroChip, IsZeroConfig}, + Challenges, SubCircuit, SubCircuitConfig, + }, + witness::{ + Block, DataTable, Format, RlpFsmWitnessGen, RlpFsmWitnessRow, RlpTag, RomTableRow, State, + State::{DecodeTagStart, End}, + Tag, + Tag::{BeginList, EndList, TxType}, + Transaction, + }, +}; use eth_types::Field; use gadgets::{ binary_number::{BinaryNumberChip, BinaryNumberConfig}, @@ -23,21 +35,9 @@ use halo2_proofs::{ poly::Rotation, }; use itertools::Itertools; +use std::marker::PhantomData; use strum::IntoEnumIterator; -use crate::{ - evm_circuit::util::constraint_builder::{BaseConstraintBuilder, ConstrainBuilderCommon}, - table::{LookupTable, RlpFsmRlpTable, U8Table}, - util::{Challenges, SubCircuit, SubCircuitConfig}, - witness::{ - Block, DataTable, Format, RlpFsmWitnessGen, RlpFsmWitnessRow, RlpTag, RomTableRow, State, - State::{DecodeTagStart, End}, - Tag, - Tag::{BeginList, EndList, TxType}, - Transaction, - }, -}; - /// Data table allows us a lookup argument from the RLP circuit to check the byte value at an index /// while decoding a tx of a given format. #[derive(Clone, Copy, Debug)] @@ -279,7 +279,7 @@ pub struct RlpCircuitConfig { data_table: RlpFsmDataTable, /// ROM table rom_table: RlpFsmRomTable, - /// Range256 table + /// Range u8 table u8_table: U8Table, } @@ -619,6 +619,7 @@ impl RlpCircuitConfig { cmp_enabled, |meta| meta.query_advice(byte_value, Rotation::cur()), |_| $value.expr(), + u8_table.into(), ); }; } @@ -629,6 +630,7 @@ impl RlpCircuitConfig { cmp_enabled, |_| $value.expr(), |meta| meta.query_advice(byte_value, Rotation::cur()), + u8_table.into(), ); }; } @@ -711,12 +713,14 @@ impl RlpCircuitConfig { cmp_enabled, |meta| meta.query_advice(tag_idx, Rotation::cur()), |meta| meta.query_advice(tag_length, Rotation::cur()), + u8_table.into(), ); let mlength_lte_0x20 = ComparatorChip::configure( meta, cmp_enabled, |meta| meta.query_advice(max_length, Rotation::cur()), |_meta| 0x20.expr(), + u8_table.into(), ); let depth_check = IsEqualChip::configure( meta, diff --git a/zkevm-circuits/src/rlp_circuit_fsm/test.rs b/zkevm-circuits/src/rlp_circuit_fsm/test.rs index 91a6198c5d..c770dac4b0 100644 --- a/zkevm-circuits/src/rlp_circuit_fsm/test.rs +++ b/zkevm-circuits/src/rlp_circuit_fsm/test.rs @@ -52,7 +52,7 @@ fn test_eip_155_tx() { _marker: Default::default(), }; - let mock_prover = MockProver::run(14, &rlp_circuit, vec![]); + let mock_prover = MockProver::run(17, &rlp_circuit, vec![]); assert!(mock_prover.is_ok()); let mock_prover = mock_prover.unwrap(); if let Err(errors) = mock_prover.verify_par() { @@ -72,7 +72,7 @@ fn test_pre_eip155_tx() { _marker: Default::default(), }; - let mock_prover = MockProver::run(16, &rlp_circuit, vec![]); + let mock_prover = MockProver::run(17, &rlp_circuit, vec![]); assert!(mock_prover.is_ok()); let mock_prover = mock_prover.unwrap(); if let Err(errors) = mock_prover.verify_par() { @@ -99,7 +99,7 @@ fn test_l1_msg_tx() { _marker: Default::default(), }; - let mock_prover = MockProver::run(16, &rlp_circuit, vec![]); + let mock_prover = MockProver::run(14, &rlp_circuit, vec![]); assert!(mock_prover.is_ok()); let mock_prover = mock_prover.unwrap(); @@ -126,7 +126,7 @@ fn test_eip1559_tx() { _marker: Default::default(), }; - let mock_prover = MockProver::run(16, &rlp_circuit, vec![]); + let mock_prover = MockProver::run(14, &rlp_circuit, vec![]); assert!(mock_prover.is_ok()); let mock_prover = mock_prover.unwrap(); if let Err(errors) = mock_prover.verify_par() { diff --git a/zkevm-circuits/src/super_circuit.rs b/zkevm-circuits/src/super_circuit.rs index f56af7b484..68efeea3dd 100644 --- a/zkevm-circuits/src/super_circuit.rs +++ b/zkevm-circuits/src/super_circuit.rs @@ -255,6 +255,7 @@ impl SubCircuitConfig for SuperCircuitConfig { keccak_table: keccak_table.clone(), rlp_table, sig_table, + u8_table, u16_table, challenges: challenges_expr.clone(), }, diff --git a/zkevm-circuits/src/tx_circuit.rs b/zkevm-circuits/src/tx_circuit.rs index c355430e82..4a7edaacca 100644 --- a/zkevm-circuits/src/tx_circuit.rs +++ b/zkevm-circuits/src/tx_circuit.rs @@ -16,17 +16,41 @@ use crate::{ evm_circuit::util::constraint_builder::{BaseConstraintBuilder, ConstrainBuilderCommon}, sig_circuit::SigCircuit, table::{ + BlockContextFieldTag::CumNumTxs, BlockTable, KeccakTable, LookupTable, RlpFsmRlpTable as RlpTable, SigTable, TxFieldTag, - TxTable, + TxFieldTag::{ + BlockNumber, CallData, CallDataGasCost, CallDataLength, CallDataRLC, CalleeAddress, + CallerAddress, ChainID, Gas, GasPrice, IsCreate, Nonce, SigR, SigS, SigV, + TxDataGasCost, TxHashLength, TxHashRLC, TxSignHash, TxSignLength, TxSignRLC, + }, + TxTable, U16Table, U8Table, + }, + util::{ + is_zero::{IsZeroChip, IsZeroConfig}, + keccak, random_linear_combine_word as rlc, rlc_be_bytes, SubCircuit, SubCircuitConfig, }, - util::{keccak, random_linear_combine_word as rlc, SubCircuit, SubCircuitConfig}, witness, - witness::{rlp_fsm::Tag, RlpTag, Transaction}, + witness::{ + rlp_fsm::Tag, + Format::{L1MsgHash, TxHashEip155, TxHashPreEip155, TxSignEip155, TxSignPreEip155}, + RlpTag, + RlpTag::{GasCost, Len, Null, RLC}, + Tag::TxType as RLPTxType, + Transaction, + }, }; use bus_mapping::circuit_input_builder::keccak_inputs_sign_verify; -use eth_types::{sign_types::SignData, Address, Field, ToAddress, ToLittleEndian, ToScalar}; +use eth_types::{ + geth_types::{ + TxType, + TxType::{Eip155, L1Msg, PreEip155}, + }, + sign_types::SignData, + Address, Field, ToAddress, ToLittleEndian, ToScalar, +}; use gadgets::{ binary_number::{BinaryNumberChip, BinaryNumberConfig}, + comparator::{ComparatorChip, ComparatorConfig, ComparatorInstruction}, is_equal::{IsEqualChip, IsEqualConfig, IsEqualInstruction}, util::{and, not, select, sum, Expr}, }; @@ -43,35 +67,12 @@ use std::{ marker::PhantomData, }; -use crate::{ - table::TxFieldTag::{ - BlockNumber, CallData, CallDataGasCost, CallDataLength, CallDataRLC, CalleeAddress, - CallerAddress, Gas, GasPrice, IsCreate, Nonce, SigR, SigS, SigV, TxDataGasCost, - TxHashLength, TxHashRLC, TxSignHash, TxSignLength, TxSignRLC, - }, - util::is_zero::{IsZeroChip, IsZeroConfig}, -}; #[cfg(feature = "onephase")] use halo2_proofs::plonk::FirstPhase as SecondPhase; use halo2_proofs::plonk::Fixed; #[cfg(not(feature = "onephase"))] use halo2_proofs::plonk::SecondPhase; -use crate::{ - table::{BlockContextFieldTag::CumNumTxs, TxFieldTag::ChainID, U16Table}, - util::rlc_be_bytes, - witness::{ - Format::{L1MsgHash, TxHashEip155, TxHashPreEip155, TxSignEip155, TxSignPreEip155}, - RlpTag::{GasCost, Len, Null, RLC}, - Tag::TxType as RLPTxType, - }, -}; -use eth_types::geth_types::{ - TxType, - TxType::{Eip155, L1Msg, PreEip155}, -}; -use gadgets::comparator::{ComparatorChip, ComparatorConfig, ComparatorInstruction}; - /// Number of rows of one tx occupies in the fixed part of tx table pub const TX_LEN: usize = 22; /// Offset of TxHash tag in the tx table @@ -106,6 +107,7 @@ pub struct TxCircuitConfig { // Whether tag's RLP-encoded value is 0x80 = rlp([]) is_none: Column, + u8_table: U8Table, u16_table: U16Table, /// Verify if the tx_id is zero or not. @@ -165,6 +167,8 @@ pub struct TxCircuitConfigArgs { pub rlp_table: RlpTable, /// SigTable pub sig_table: SigTable, + /// Reusable u8 lookup table, + pub u8_table: U8Table, /// Reusable u16 lookup table, pub u16_table: U16Table, /// Challenges @@ -183,6 +187,7 @@ impl SubCircuitConfig for TxCircuitConfig { keccak_table, rlp_table, sig_table, + u8_table, u16_table, challenges: _, }: Self::ConfigArgs, @@ -686,6 +691,7 @@ impl SubCircuitConfig for TxCircuitConfig { |meta| meta.query_fixed(q_enable, Rotation::cur()), |meta| meta.query_advice(tx_table.tx_id, Rotation::cur()), |meta| meta.query_advice(cum_num_txs, Rotation::cur()), + u8_table.into(), ); meta.create_gate("tx_id <= cum_num_txs", |meta| { @@ -875,6 +881,7 @@ impl SubCircuitConfig for TxCircuitConfig { tx_type_bits, rlp_tag, is_none, + u8_table, u16_table, tx_id_is_zero, value_is_zero, diff --git a/zkevm-circuits/src/tx_circuit/dev.rs b/zkevm-circuits/src/tx_circuit/dev.rs index 6f8c16886a..7c6fa7057a 100644 --- a/zkevm-circuits/src/tx_circuit/dev.rs +++ b/zkevm-circuits/src/tx_circuit/dev.rs @@ -6,7 +6,9 @@ pub use super::TxCircuit; use crate::{ sig_circuit::{SigCircuit, SigCircuitConfig, SigCircuitConfigArgs}, - table::{BlockTable, KeccakTable, RlpFsmRlpTable as RlpTable, SigTable, TxTable, U16Table}, + table::{ + BlockTable, KeccakTable, RlpFsmRlpTable as RlpTable, SigTable, TxTable, U16Table, U8Table, + }, tx_circuit::{TxCircuitConfig, TxCircuitConfigArgs}, util::{Challenges, SubCircuit, SubCircuitConfig}, witness::Transaction, @@ -29,6 +31,8 @@ pub struct TxCircuitTesterConfigArgs { pub keccak_table: KeccakTable, /// SigTable pub sig_table: SigTable, + /// u8 lookup table, + pub u8_table: U8Table, /// u16 lookup table, pub u16_table: U16Table, /// Challenges @@ -42,6 +46,8 @@ pub struct TxCircuitTesterConfig { // SigTable is assigned inside SigCircuit sig_config: SigCircuitConfig, /// u16 lookup table, + pub u8_table: U8Table, + /// u16 lookup table, pub u16_table: U16Table, } @@ -56,6 +62,7 @@ impl SubCircuitConfig for TxCircuitTesterConfig { keccak_table, rlp_table, sig_table, + u8_table, u16_table, challenges, }: Self::ConfigArgs, @@ -76,6 +83,7 @@ impl SubCircuitConfig for TxCircuitTesterConfig { tx_table, keccak_table, rlp_table, + u8_table, u16_table, challenges, }, @@ -83,6 +91,7 @@ impl SubCircuitConfig for TxCircuitTesterConfig { TxCircuitTesterConfig { tx_config, sig_config, + u8_table, u16_table, } } @@ -150,6 +159,7 @@ impl Circuit for TxCircuitTester { 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 challenges = Challenges::construct(meta); @@ -171,6 +181,7 @@ impl Circuit for TxCircuitTester { tx_table, keccak_table, rlp_table, + u8_table, u16_table, challenges, }, @@ -178,6 +189,7 @@ impl Circuit for TxCircuitTester { TxCircuitTesterConfig { tx_config, sig_config, + u8_table, u16_table, } }; @@ -191,6 +203,7 @@ impl Circuit for TxCircuitTester { mut layouter: impl Layouter, ) -> Result<(), Error> { let challenges = challenges.values(&layouter); + config.u8_table.load(&mut layouter)?; config.u16_table.load(&mut layouter)?; let padding_txs = (self.tx_circuit.txs.len()..self.tx_circuit.max_txs)