From 7f8ba1737bd15c582704c1d53c77b50941975441 Mon Sep 17 00:00:00 2001 From: Eduard S Date: Thu, 30 Jun 2022 18:26:40 +0200 Subject: [PATCH 01/26] WIP --- zkevm-circuits/src/evm_circuit.rs | 193 ++++++++++++++++++++++++++-- zkevm-circuits/src/lib.rs | 1 + zkevm-circuits/src/super_circuit.rs | 34 +++++ zkevm-circuits/src/tx_circuit.rs | 67 +++++++--- 4 files changed, 264 insertions(+), 31 deletions(-) create mode 100644 zkevm-circuits/src/super_circuit.rs diff --git a/zkevm-circuits/src/evm_circuit.rs b/zkevm-circuits/src/evm_circuit.rs index 3f3b6793f7..9e923b81b1 100644 --- a/zkevm-circuits/src/evm_circuit.rs +++ b/zkevm-circuits/src/evm_circuit.rs @@ -139,14 +139,161 @@ impl EvmCircuit { } } +use crate::{ + evm_circuit::witness::{BlockContext, Bytecode, RwMap, Transaction}, + rw_table::RwTable, +}; + +pub fn load_txs( + tx_table: &[Column; 4], + layouter: &mut impl Layouter, + txs: &[Transaction], + randomness: F, +) -> Result<(), Error> { + layouter.assign_region( + || "tx table", + |mut region| { + let mut offset = 0; + for column in tx_table { + region.assign_advice( + || "tx table all-zero row", + *column, + offset, + || Ok(F::zero()), + )?; + } + offset += 1; + + for tx in txs.iter() { + for row in tx.table_assignments(randomness) { + for (column, value) in tx_table.iter().zip_eq(row) { + region.assign_advice( + || format!("tx table row {}", offset), + *column, + offset, + || Ok(value), + )?; + } + offset += 1; + } + } + Ok(()) + }, + ) +} + +pub fn load_rws( + rw_table: &RwTable, + layouter: &mut impl Layouter, + rws: &RwMap, + randomness: F, +) -> Result<(), Error> { + layouter.assign_region( + || "rw table", + |mut region| { + let mut offset = 0; + rw_table.assign(&mut region, offset, &Default::default())?; + offset += 1; + + let mut rows = rws + .0 + .values() + .flat_map(|rws| rws.iter()) + .collect::>(); + + rows.sort_by_key(|a| a.rw_counter()); + let mut expected_rw_counter = 1; + for rw in rows { + assert!(rw.rw_counter() == expected_rw_counter); + expected_rw_counter += 1; + + rw_table.assign(&mut region, offset, &rw.table_assignment(randomness))?; + offset += 1; + } + Ok(()) + }, + ) +} + +pub fn load_bytecodes( + bytecode_table: &[Column; 5], + layouter: &mut impl Layouter, + bytecodes: &[Bytecode], + randomness: F, +) -> Result<(), Error> { + layouter.assign_region( + || "bytecode table", + |mut region| { + let mut offset = 0; + for column in bytecode_table { + region.assign_advice( + || "bytecode table all-zero row", + *column, + offset, + || Ok(F::zero()), + )?; + } + offset += 1; + + for bytecode in bytecodes.iter() { + for row in bytecode.table_assignments(randomness) { + for (column, value) in bytecode_table.iter().zip_eq(row) { + region.assign_advice( + || format!("bytecode table row {}", offset), + *column, + offset, + || Ok(value), + )?; + } + offset += 1; + } + } + Ok(()) + }, + ) +} +pub fn load_block( + block_table: &[Column; 3], + layouter: &mut impl Layouter, + block: &BlockContext, + randomness: F, +) -> Result<(), Error> { + layouter.assign_region( + || "block table", + |mut region| { + let mut offset = 0; + for column in block_table { + region.assign_advice( + || "block table all-zero row", + *column, + offset, + || Ok(F::zero()), + )?; + } + offset += 1; + + for row in block.table_assignments(randomness) { + for (column, value) in block_table.iter().zip_eq(row) { + region.assign_advice( + || format!("block table row {}", offset), + *column, + offset, + || Ok(value), + )?; + } + offset += 1; + } + + Ok(()) + }, + ) +} + #[cfg(any(feature = "test", test))] pub mod test { + use super::*; use crate::{ - evm_circuit::{ - table::FixedTableTag, - witness::{Block, BlockContext, Bytecode, RwMap, Transaction}, - EvmCircuit, - }, + evm_circuit::{table::FixedTableTag, witness::Block, EvmCircuit}, rw_table::RwTable, util::Expr, }; @@ -157,7 +304,6 @@ pub mod test { plonk::{Advice, Circuit, Column, ConstraintSystem, Error}, poly::Rotation, }; - use itertools::Itertools; use rand::{ distributions::uniform::{SampleRange, SampleUniform}, random, thread_rng, Rng, @@ -418,14 +564,39 @@ pub mod test { .evm_circuit .load_fixed_table(&mut layouter, self.fixed_table_tags.clone())?; config.evm_circuit.load_byte_table(&mut layouter)?; - config.load_txs(&mut layouter, &self.block.txs, self.block.randomness)?; - config.load_rws(&mut layouter, &self.block.rws, self.block.randomness)?; - config.load_bytecodes( + // config.load_txs(&mut layouter, &self.block.txs, self.block.randomness)?; + // config.load_rws(&mut layouter, &self.block.rws, self.block.randomness)?; + // config.load_bytecodes( + // &mut layouter, + // self.block.bytecodes.values(), + // self.block.randomness, + // )?; + // config.load_block(&mut layouter, &self.block.context, + // self.block.randomness)?; + load_txs( + &config.tx_table, + &mut layouter, + &self.block.txs, + self.block.randomness, + )?; + load_rws( + &config.rw_table, + &mut layouter, + &self.block.rws, + self.block.randomness, + )?; + load_bytecodes( + &config.bytecode_table, + &mut layouter, + &self.block.bytecodes, + self.block.randomness, + )?; + load_block( + &config.block_table, &mut layouter, - self.block.bytecodes.values(), + &self.block.context, self.block.randomness, )?; - config.load_block(&mut layouter, &self.block.context, self.block.randomness)?; config .evm_circuit .assign_block_exact(&mut layouter, &self.block) diff --git a/zkevm-circuits/src/lib.rs b/zkevm-circuits/src/lib.rs index 31b01b6338..c38d781143 100644 --- a/zkevm-circuits/src/lib.rs +++ b/zkevm-circuits/src/lib.rs @@ -20,6 +20,7 @@ pub mod bytecode_circuit; pub mod evm_circuit; pub mod rw_table; pub mod state_circuit; +pub mod super_circuit; #[cfg(test)] pub mod test_util; pub mod tx_circuit; diff --git a/zkevm-circuits/src/super_circuit.rs b/zkevm-circuits/src/super_circuit.rs new file mode 100644 index 0000000000..c8541b89ab --- /dev/null +++ b/zkevm-circuits/src/super_circuit.rs @@ -0,0 +1,34 @@ +//! Mario Kart: Super Circuit +//! ⠀⠀⠀⠀⠀⠀⠀⢀⣀⣀⡀⠀⠀⠀⠀⠀⠀⠀ +//! ⠀⠀⠀⠀⡠⣴⣮⣷⣶⡶⣾⣽⣶⢤⡀⠀⠀⠀ +//! ⠀⠀⢠⣾⣿⢧⣾⣿⣿⣧⣿⣿⣿⣷⡱⡄⠀⠀ +//! ⠀⣠⣿⣿⣯⣿⣿⣿⣿⡿⣼⣻⠿⠟⠛⠻⢦⡀ +//! ⡼⠁⢿⣟⣎⣿⣿⠿⠟⠃⠉⠀⠀⠀⠀⠀⠀⣷ +//! ⢳⡀⠀⠀⠀⠀⠀⠀⠀⣀⡠⡤⢲⣾⡏⢱⡠⠃ +//! ⠀⠉⠲⡲⠒⠒⡖⠚⠿⢿⠃⠡⡀⠉⢁⠞⠀⠀ +//! ⠀⠀⠀⠘⠳⢄⣘⢤⣀⠈⢂⣤⠴⠚⠁⠀⠀⠀ +//! ⠀⠀⠀⠀⠀⠀⠀⠉⠉⠉⠁⠀⠀⠀⠀⠀⠀⠀ + +#![allow(missing_docs)] +use halo2_proofs::{circuit::Layouter, plonk::*}; + +use crate::evm_circuit::EvmCircuit; +use crate::tx_circuit::TxCircuit; + +use crate::{ + evm_circuit::witness::{BlockContext, Bytecode, RwMap, Transaction}, + rw_table::RwTable, +}; + +#[derive(Clone)] +pub struct SuperCircuit { + tx_table: [Column; 4], + rw_table: RwTable, + bytecode_table: [Column; 5], + block_table: [Column; 3], + evm_circuit: EvmCircuit, + tx_circuit: TxCircuit, +} + +#[cfg(test)] +mod super_circuit_tests {} diff --git a/zkevm-circuits/src/tx_circuit.rs b/zkevm-circuits/src/tx_circuit.rs index a5de278299..e43a152c3b 100644 --- a/zkevm-circuits/src/tx_circuit.rs +++ b/zkevm-circuits/src/tx_circuit.rs @@ -176,12 +176,25 @@ pub struct TxCircuitConfig { _marker: PhantomData, } +/// TxTable columns +#[derive(Clone, Debug)] +pub struct TxTable { + pub tx_id: Column, + pub tag: Column, + pub index: Column, + pub value: Column, +} + impl TxCircuitConfig { - fn new(meta: &mut ConstraintSystem) -> Self { - let tx_id = meta.advice_column(); - let tag = meta.advice_column(); - let index = meta.advice_column(); - let value = meta.advice_column(); + fn new(meta: &mut ConstraintSystem, tx_table: TxTable) -> Self { + // let tx_id = meta.advice_column(); + // let tag = meta.advice_column(); + // let index = meta.advice_column(); + // let value = meta.advice_column(); + let tx_id = tx_table.tx_id; + let tag = tx_table.tag; + let index = tx_table.index; + let value = tx_table.value; meta.enable_equality(value); // This gate is used just to get the array of expressions from the power of @@ -244,23 +257,12 @@ pub struct TxCircuit pub chain_id: u64, } -impl Circuit - for TxCircuit +impl + TxCircuit { - type Config = TxCircuitConfig; - type FloorPlanner = SimpleFloorPlanner; - - fn without_witnesses(&self) -> Self { - Self::default() - } - - fn configure(meta: &mut ConstraintSystem) -> Self::Config { - TxCircuitConfig::new(meta) - } - - fn synthesize( + pub fn assign( &self, - config: Self::Config, + config: TxCircuitConfig, mut layouter: impl Layouter, ) -> Result<(), Error> { assert!(self.txs.len() <= MAX_TXS); @@ -391,6 +393,31 @@ impl Circuit } } +impl Circuit + for TxCircuit +{ + type Config = TxCircuitConfig; + type FloorPlanner = SimpleFloorPlanner; + + fn without_witnesses(&self) -> Self { + Self::default() + } + + fn configure(meta: &mut ConstraintSystem) -> Self::Config { + let tx_table = TxTable { + tx_id: meta.advice_column(), + tag: meta.advice_column(), + index: meta.advice_column(), + value: meta.advice_column(), + }; + TxCircuitConfig::new(meta, tx_table) + } + + fn synthesize(&self, config: Self::Config, layouter: impl Layouter) -> Result<(), Error> { + self.assign(config, layouter) + } +} + #[cfg(test)] mod tx_circuit_tests { use super::*; From 3723f01c47df0a216707b945a22b3f537d44b86b Mon Sep 17 00:00:00 2001 From: Eduard S Date: Fri, 1 Jul 2022 16:10:41 +0200 Subject: [PATCH 02/26] Join EVM + TxCircuit --- zkevm-circuits/src/super_circuit.rs | 321 ++++++++++++++++++- zkevm-circuits/src/tx_circuit.rs | 72 ++++- zkevm-circuits/src/tx_circuit/sign_verify.rs | 2 +- 3 files changed, 374 insertions(+), 21 deletions(-) diff --git a/zkevm-circuits/src/super_circuit.rs b/zkevm-circuits/src/super_circuit.rs index c8541b89ab..20b2f7b646 100644 --- a/zkevm-circuits/src/super_circuit.rs +++ b/zkevm-circuits/src/super_circuit.rs @@ -10,25 +10,334 @@ //! ⠀⠀⠀⠀⠀⠀⠀⠉⠉⠉⠁⠀⠀⠀⠀⠀⠀⠀ #![allow(missing_docs)] -use halo2_proofs::{circuit::Layouter, plonk::*}; +// use halo2_proofs::plonk::*; -use crate::evm_circuit::EvmCircuit; -use crate::tx_circuit::TxCircuit; +use crate::tx_circuit::{sign_verify, TxCircuit, TxCircuitConfig, TxTable}; +use crate::util::Expr; use crate::{ - evm_circuit::witness::{BlockContext, Bytecode, RwMap, Transaction}, + evm_circuit::{ + table::{FixedTableTag, LookupTable}, + witness::{Block, BlockContext, Bytecode, RwMap, Transaction as WitTransaction}, + EvmCircuit, {load_block, load_bytecodes, load_rws, load_txs}, + }, rw_table::RwTable, }; +use eth_types::{geth_types::Transaction, Field}; +use halo2_proofs::{ + arithmetic::CurveAffine, + circuit::{Layouter, SimpleFloorPlanner}, + // dev::{MockProver, VerifyFailure}, + plonk::{Advice, Circuit, Column, ConstraintSystem, Error, Expression}, + poly::Rotation, +}; #[derive(Clone)] -pub struct SuperCircuit { +pub struct SuperCircuitConfig { tx_table: [Column; 4], rw_table: RwTable, bytecode_table: [Column; 5], block_table: [Column; 3], evm_circuit: EvmCircuit, + tx_circuit: TxCircuitConfig, +} + +#[derive(Default)] +pub struct SuperCircuit { + block: Block, + fixed_table_tags: Vec, tx_circuit: TxCircuit, } +impl + SuperCircuit +{ + pub fn get_num_rows_required(block: &Block) -> usize { + let mut cs = ConstraintSystem::default(); + let config = Self::configure(&mut cs); + config.evm_circuit.get_num_rows_required(block) + } +} + +impl Circuit + for SuperCircuit +{ + type Config = SuperCircuitConfig; + type FloorPlanner = SimpleFloorPlanner; + + fn without_witnesses(&self) -> Self { + Self::default() + } + + fn configure(meta: &mut ConstraintSystem) -> Self::Config { + let tx_table = [(); 4].map(|_| meta.advice_column()); + let rw_table = RwTable::construct(meta); + let bytecode_table = [(); 5].map(|_| meta.advice_column()); + let block_table = [(); 3].map(|_| meta.advice_column()); + + // This gate is used just to get the array of expressions from the power of + // randomness instance column, so that later on we don't need to query + // columns everywhere, and can pass the power of randomness array + // expression everywhere. The gate itself doesn't add any constraints. + let power_of_randomness = { + let columns = [(); sign_verify::POW_RAND_SIZE].map(|_| meta.instance_column()); + let mut power_of_randomness = None; + + meta.create_gate("", |meta| { + power_of_randomness = + Some(columns.map(|column| meta.query_instance(column, Rotation::cur()))); + + [0.expr()] + }); + + power_of_randomness.unwrap() + }; + + Self::Config { + tx_table, + rw_table, + bytecode_table, + block_table, + evm_circuit: EvmCircuit::configure( + meta, + power_of_randomness[..31] + .iter() + .cloned() + .collect::>>() + .try_into() + .unwrap(), + &tx_table, + &rw_table, + &bytecode_table, + &block_table, + ), + tx_circuit: TxCircuitConfig::new( + meta, + power_of_randomness, + TxTable { + tx_id: tx_table[0], + tag: tx_table[1], + index: tx_table[2], + value: tx_table[3], + }, + ), + } + } + + fn synthesize( + &self, + config: Self::Config, + mut layouter: impl Layouter, + ) -> Result<(), Error> { + config + .evm_circuit + .load_fixed_table(&mut layouter, self.fixed_table_tags.clone())?; + config.evm_circuit.load_byte_table(&mut layouter)?; + load_txs( + &config.tx_table, + &mut layouter, + &self.block.txs, + self.block.randomness, + )?; + load_rws( + &config.rw_table, + &mut layouter, + &self.block.rws, + self.block.randomness, + )?; + load_bytecodes( + &config.bytecode_table, + &mut layouter, + &self.block.bytecodes, + self.block.randomness, + )?; + load_block( + &config.block_table, + &mut layouter, + &self.block.context, + self.block.randomness, + )?; + config + .evm_circuit + .assign_block_exact(&mut layouter, &self.block)?; + self.tx_circuit.synthesize(config.tx_circuit, layouter)?; + Ok(()) + } +} + #[cfg(test)] -mod super_circuit_tests {} +mod super_circuit_tests { + use super::*; + use crate::{ + evm_circuit::witness::block_convert, + test_util::{run_test_circuits, BytecodeTestConfig}, + tx_circuit::sign_verify::POW_RAND_SIZE, + }; + use bus_mapping::mock::BlockData; + use eth_types::{address, bytecode, geth_types::GethData, Word}; + use ethers_core::{ + types::{NameOrAddress, TransactionRequest}, + utils::keccak256, + }; + use ethers_signers::{LocalWallet, Signer}; + use group::{Curve, Group}; + use halo2_proofs::dev::{MockProver, VerifyFailure}; + use mock::{TestContext, MOCK_CHAIN_ID}; + use rand::{CryptoRng, Rng, SeedableRng}; + use rand_chacha::ChaCha20Rng; + use secp256k1::Secp256k1Affine; + use strum::IntoEnumIterator; + + struct Inputs { + block: Block, + txs: Vec, + aux_generator: Secp256k1Affine, + } + + fn run_test_circuit( + inputs: Inputs, + fixed_table_tags: Vec, + ) -> Result<(), Vec> { + let Inputs { + block, + txs, + aux_generator, + } = inputs; + + let log2_ceil = |n| u32::BITS - (n as u32).leading_zeros() - (n & (n - 1) == 0) as u32; + + let num_rows_required_for_steps = + SuperCircuit::::get_num_rows_required(&block); + + let k = log2_ceil( + 64 + fixed_table_tags + .iter() + .map(|tag| tag.build::().count()) + .sum::(), + ); + let k = k.max(log2_ceil( + 64 + block + .bytecodes + .iter() + .map(|bytecode| bytecode.bytes.len()) + .sum::(), + )); + let k = k.max(log2_ceil(64 + num_rows_required_for_steps)); + let k = k + 1; + log::debug!("evm circuit uses k = {}", k); + + let mut instance: Vec> = (1..POW_RAND_SIZE + 1) + .map(|exp| vec![block.randomness.pow(&[exp as u64, 0, 0, 0]); (1 << k) - 64]) + .collect(); + // SignVerifyChip -> ECDSAChip -> MainGate instance column + instance.push(vec![]); + + let chain_id = block.context.chain_id; + let tx_circuit = TxCircuit::new(aux_generator, block.randomness, chain_id.as_u64(), txs); + let circuit = SuperCircuit:: { + block, + fixed_table_tags, + tx_circuit, + }; + let prover = MockProver::::run(k, &circuit, instance).unwrap(); + prover.verify() + } + + fn run_test_circuit_complete_fixed_table( + inputs: Inputs, + ) -> Result<(), Vec> { + const MAX_TXS: usize = 1; + const MAX_CALLDATA: usize = 32; + + run_test_circuit::(inputs, FixedTableTag::iter().collect()) + } + + #[test] + fn test_super_circuit() { + let mut rng = ChaCha20Rng::seed_from_u64(2); + + let chain_id = (*MOCK_CHAIN_ID).as_u64(); + + let bytecode = bytecode! { + GAS + STOP + }; + + let wallet_a = LocalWallet::new(&mut rng).with_chain_id(chain_id); + + let addr_a = wallet_a.address(); + let addr_b = address!("0x000000000000000000000000000000000000BBBB"); + + // Create a custom tx setting Gas to + let block: GethData = TestContext::<2, 1>::new( + None, + |accs| { + accs[0] + .address(addr_b) + .balance(Word::from(1u64 << 20)) + .code(bytecode); + accs[1].address(addr_a).balance(Word::from(1u64 << 20)); + }, + |mut txs, accs| { + txs[0] + .from(accs[1].address) + .to(accs[0].address) + .gas(Word::from(1_000_000u64)); + }, + |block, _tx| block.number(0xcafeu64), + ) + .unwrap() + .into(); + + let txs: Vec = block + .eth_block + .transactions + .iter() + .map(|tx| { + let req = TransactionRequest::new() + .from(tx.from) + .to(tx.to.unwrap()) + .nonce(tx.nonce) + .value(tx.value) + .data(tx.input.clone()) + .gas(tx.gas) + .gas_price(tx.gas_price.unwrap()); + let tx_rlp = req.rlp(chain_id); + let sighash = keccak256(tx_rlp.as_ref()).into(); + let sig = wallet_a.sign_hash(sighash, true); + Transaction { + from: tx.from, + to: tx.to, + gas_limit: tx.gas, + gas_price: tx.gas_price.unwrap(), + value: tx.value, + call_data: tx.input.clone(), + nonce: tx.nonce, + v: sig.v, + r: sig.r, + s: sig.s, + ..Transaction::default() + } + }) + .collect(); + + let mut builder = BlockData::new_from_geth_data(block.clone()).new_circuit_input_builder(); + assert_eq!(builder.block.chain_id.as_u64(), chain_id); + + builder + .handle_block(&block.eth_block, &block.geth_traces) + .expect("could not handle block tx"); + let block = block_convert(&builder.block, &builder.code_db); + let txs = Vec::new(); + + let aux_generator = + ::CurveExt::random(&mut rng).to_affine(); + let inputs = Inputs { + block, + txs, + aux_generator, + }; + + assert_eq!(run_test_circuit_complete_fixed_table(inputs), Ok(())); + } +} diff --git a/zkevm-circuits/src/tx_circuit.rs b/zkevm-circuits/src/tx_circuit.rs index e43a152c3b..f850e2646b 100644 --- a/zkevm-circuits/src/tx_circuit.rs +++ b/zkevm-circuits/src/tx_circuit.rs @@ -13,8 +13,9 @@ use eth_types::{ use ff::PrimeField; use group::GroupEncoding; use halo2_proofs::{ + // arithmetic::CurveAffine, circuit::{AssignedCell, Layouter, Region, SimpleFloorPlanner}, - plonk::{Advice, Circuit, Column, ConstraintSystem, Error}, + plonk::{Advice, Circuit, Column, ConstraintSystem, Error, Expression}, poly::Rotation, }; use itertools::Itertools; @@ -23,6 +24,7 @@ use libsecp256k1; use log::error; use num::Integer; use num_bigint::BigUint; +// use rand_core::RngCore; use rlp::RlpStream; use secp256k1::Secp256k1Affine; use sha3::{Digest, Keccak256}; @@ -186,7 +188,11 @@ pub struct TxTable { } impl TxCircuitConfig { - fn new(meta: &mut ConstraintSystem, tx_table: TxTable) -> Self { + pub fn new( + meta: &mut ConstraintSystem, + power_of_randomness: [Expression; sign_verify::POW_RAND_SIZE], + tx_table: TxTable, + ) -> Self { // let tx_id = meta.advice_column(); // let tag = meta.advice_column(); // let index = meta.advice_column(); @@ -201,19 +207,20 @@ impl TxCircuitConfig { // randomness instance column, so that later on we don't need to query // columns everywhere, and can pass the power of randomness array // expression everywhere. The gate itself doesn't add any constraints. - let power_of_randomness = { - let columns = [(); sign_verify::POW_RAND_SIZE].map(|_| meta.instance_column()); - let mut power_of_randomness = None; + // let power_of_randomness = { + // let columns = [(); sign_verify::POW_RAND_SIZE].map(|_| + // meta.instance_column()); let mut power_of_randomness = None; - meta.create_gate("power of randomness", |meta| { - power_of_randomness = - Some(columns.map(|column| meta.query_instance(column, Rotation::cur()))); + // meta.create_gate("power of randomness", |meta| { + // power_of_randomness = + // Some(columns.map(|column| meta.query_instance(column, + // Rotation::cur()))); - [0.expr()] - }); + // [0.expr()] + // }); - power_of_randomness.unwrap() - }; + // power_of_randomness.unwrap() + // }; let sign_verify = SignVerifyConfig::new(meta, power_of_randomness); Self { @@ -245,7 +252,7 @@ impl TxCircuitConfig { } /// Tx Circuit for verifying transaction signatures -#[derive(Default)] +#[derive(Clone, Default)] pub struct TxCircuit { /// SignVerify chip pub sign_verify: SignVerifyChip, @@ -260,6 +267,24 @@ pub struct TxCircuit impl TxCircuit { + pub fn new( + aux_generator: Secp256k1Affine, + randomness: F, + chain_id: u64, + txs: Vec, + ) -> Self { + TxCircuit:: { + sign_verify: SignVerifyChip { + aux_generator, + window_size: 2, + _marker: PhantomData, + }, + randomness, + txs, + chain_id, + } + } + pub fn assign( &self, config: TxCircuitConfig, @@ -410,7 +435,26 @@ impl Circuit index: meta.advice_column(), value: meta.advice_column(), }; - TxCircuitConfig::new(meta, tx_table) + + // This gate is used just to get the array of expressions from the power of + // randomness instance column, so that later on we don't need to query + // columns everywhere, and can pass the power of randomness array + // expression everywhere. The gate itself doesn't add any constraints. + let power_of_randomness = { + let columns = [(); sign_verify::POW_RAND_SIZE].map(|_| meta.instance_column()); + let mut power_of_randomness = None; + + meta.create_gate("", |meta| { + power_of_randomness = + Some(columns.map(|column| meta.query_instance(column, Rotation::cur()))); + + [0.expr()] + }); + + power_of_randomness.unwrap() + }; + + TxCircuitConfig::new(meta, power_of_randomness, tx_table) } fn synthesize(&self, config: Self::Config, layouter: impl Layouter) -> Result<(), Error> { diff --git a/zkevm-circuits/src/tx_circuit/sign_verify.rs b/zkevm-circuits/src/tx_circuit/sign_verify.rs index 64c82061c4..736a7653e4 100644 --- a/zkevm-circuits/src/tx_circuit/sign_verify.rs +++ b/zkevm-circuits/src/tx_circuit/sign_verify.rs @@ -46,7 +46,7 @@ pub const VERIF_HEIGHT: usize = 1; /// Auxiliary Gadget to verify a that a message hash is signed by the public /// key corresponding to an Ethereum Address. -#[derive(Default, Debug)] +#[derive(Clone, Default, Debug)] pub struct SignVerifyChip { /// Aux generator for EccChip pub aux_generator: Secp256k1Affine, From 44a39ba8dfbd8b03691ca5858391aa1fcaccd117 Mon Sep 17 00:00:00 2001 From: Eduard S Date: Fri, 1 Jul 2022 18:07:40 +0200 Subject: [PATCH 03/26] WIP clean --- zkevm-circuits/src/super_circuit.rs | 99 +++++++++++++++-------------- 1 file changed, 53 insertions(+), 46 deletions(-) diff --git a/zkevm-circuits/src/super_circuit.rs b/zkevm-circuits/src/super_circuit.rs index 20b2f7b646..161aa42762 100644 --- a/zkevm-circuits/src/super_circuit.rs +++ b/zkevm-circuits/src/super_circuit.rs @@ -17,13 +17,13 @@ use crate::tx_circuit::{sign_verify, TxCircuit, TxCircuitConfig, TxTable}; use crate::util::Expr; use crate::{ evm_circuit::{ - table::{FixedTableTag, LookupTable}, - witness::{Block, BlockContext, Bytecode, RwMap, Transaction as WitTransaction}, - EvmCircuit, {load_block, load_bytecodes, load_rws, load_txs}, + table::FixedTableTag, + witness::Block, + EvmCircuit, {load_block, load_bytecodes, load_rws}, }, rw_table::RwTable, }; -use eth_types::{geth_types::Transaction, Field}; +use eth_types::Field; use halo2_proofs::{ arithmetic::CurveAffine, circuit::{Layouter, SimpleFloorPlanner}, @@ -133,12 +133,12 @@ impl Circuit .evm_circuit .load_fixed_table(&mut layouter, self.fixed_table_tags.clone())?; config.evm_circuit.load_byte_table(&mut layouter)?; - load_txs( - &config.tx_table, - &mut layouter, - &self.block.txs, - self.block.randomness, - )?; + // load_txs( + // &config.tx_table, + // &mut layouter, + // &self.block.txs, + // self.block.randomness, + // )?; load_rws( &config.rw_table, &mut layouter, @@ -164,33 +164,62 @@ impl Circuit Ok(()) } } +use eth_types::{Address, U64}; +use ethers_core::{types::TransactionRequest, utils::keccak256}; +use ethers_signers::LocalWallet; +use std::collections::HashMap; + +// Testing function +pub fn sign_txs( + txs: &mut [eth_types::Transaction], + chain_id: u64, + wallets: &HashMap, +) { + for tx in txs.iter_mut() { + let wallet = wallets.get(&tx.from).unwrap(); + let req = TransactionRequest::new() + .from(tx.from) + .to(tx.to.unwrap()) + .nonce(tx.nonce) + .value(tx.value) + .data(tx.input.clone()) + .gas(tx.gas) + .gas_price(tx.gas_price.unwrap()); + let tx_rlp = req.rlp(chain_id); + let sighash = keccak256(tx_rlp.as_ref()).into(); + let sig = wallet.sign_hash(sighash, true); + tx.v = U64::from(sig.v); + tx.r = sig.r; + tx.s = sig.s; + } +} #[cfg(test)] mod super_circuit_tests { use super::*; use crate::{ evm_circuit::witness::block_convert, - test_util::{run_test_circuits, BytecodeTestConfig}, + // test_util::{run_test_circuits, BytecodeTestConfig}, tx_circuit::sign_verify::POW_RAND_SIZE, }; use bus_mapping::mock::BlockData; - use eth_types::{address, bytecode, geth_types::GethData, Word}; - use ethers_core::{ - types::{NameOrAddress, TransactionRequest}, - utils::keccak256, + use eth_types::{ + address, bytecode, + geth_types::{self, GethData}, + Word, }; use ethers_signers::{LocalWallet, Signer}; use group::{Curve, Group}; use halo2_proofs::dev::{MockProver, VerifyFailure}; use mock::{TestContext, MOCK_CHAIN_ID}; - use rand::{CryptoRng, Rng, SeedableRng}; + use rand::SeedableRng; use rand_chacha::ChaCha20Rng; use secp256k1::Secp256k1Affine; use strum::IntoEnumIterator; struct Inputs { block: Block, - txs: Vec, + txs: Vec, aux_generator: Secp256k1Affine, } @@ -268,8 +297,11 @@ mod super_circuit_tests { let addr_a = wallet_a.address(); let addr_b = address!("0x000000000000000000000000000000000000BBBB"); + let mut wallets = HashMap::new(); + wallets.insert(wallet_a.address(), wallet_a.clone()); + // Create a custom tx setting Gas to - let block: GethData = TestContext::<2, 1>::new( + let mut block: GethData = TestContext::<2, 1>::new( None, |accs| { accs[0] @@ -289,36 +321,12 @@ mod super_circuit_tests { .unwrap() .into(); - let txs: Vec = block + sign_txs(&mut block.eth_block.transactions, chain_id, &wallets); + let txs = block .eth_block .transactions .iter() - .map(|tx| { - let req = TransactionRequest::new() - .from(tx.from) - .to(tx.to.unwrap()) - .nonce(tx.nonce) - .value(tx.value) - .data(tx.input.clone()) - .gas(tx.gas) - .gas_price(tx.gas_price.unwrap()); - let tx_rlp = req.rlp(chain_id); - let sighash = keccak256(tx_rlp.as_ref()).into(); - let sig = wallet_a.sign_hash(sighash, true); - Transaction { - from: tx.from, - to: tx.to, - gas_limit: tx.gas, - gas_price: tx.gas_price.unwrap(), - value: tx.value, - call_data: tx.input.clone(), - nonce: tx.nonce, - v: sig.v, - r: sig.r, - s: sig.s, - ..Transaction::default() - } - }) + .map(|tx| geth_types::Transaction::from_eth_tx(tx)) .collect(); let mut builder = BlockData::new_from_geth_data(block.clone()).new_circuit_input_builder(); @@ -328,7 +336,6 @@ mod super_circuit_tests { .handle_block(&block.eth_block, &block.geth_traces) .expect("could not handle block tx"); let block = block_convert(&builder.block, &builder.code_db); - let txs = Vec::new(); let aux_generator = ::CurveExt::random(&mut rng).to_affine(); From 61ecc5999d2b4e43674baedad9e2e23bf1d261e6 Mon Sep 17 00:00:00 2001 From: Eduard S Date: Fri, 1 Jul 2022 18:23:20 +0200 Subject: [PATCH 04/26] WIP add bytecode circuit --- .../src/bytecode_circuit/bytecode_unroller.rs | 46 +++++++++++++------ zkevm-circuits/src/super_circuit.rs | 20 ++++++++ 2 files changed, 53 insertions(+), 13 deletions(-) diff --git a/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs b/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs index e8f86c66b2..611fb4c923 100644 --- a/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs +++ b/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs @@ -42,17 +42,26 @@ pub(crate) struct UnrolledBytecode { } #[derive(Clone, Debug)] -pub struct Config { - r: F, - minimum_rows: usize, - q_enable: Column, - q_first: Column, - q_last: Selector, +pub struct BytecodeTable { hash: Column, tag: Column, index: Column, is_code: Column, value: Column, +} + +#[derive(Clone, Debug)] +pub struct Config { + r: F, // TODO: Replace by Expression + minimum_rows: usize, + q_enable: Column, + q_first: Column, + q_last: Selector, + hash: Column, // * + tag: Column, // * + index: Column, // * + is_code: Column, // * + value: Column, // * push_rindex: Column, hash_rlc: Column, hash_length: Column, @@ -68,15 +77,19 @@ pub struct Config { } impl Config { - pub(crate) fn configure(meta: &mut ConstraintSystem, r: F) -> Self { + pub(crate) fn configure( + meta: &mut ConstraintSystem, + r: F, + bytecode_table: BytecodeTable, + ) -> Self { let q_enable = meta.fixed_column(); let q_first = meta.fixed_column(); let q_last = meta.selector(); - let hash = meta.advice_column(); - let tag = meta.advice_column(); - let index = meta.advice_column(); - let is_code = meta.advice_column(); - let value = meta.advice_column(); + let hash = bytecode_table.hash; + let tag = bytecode_table.tag; + let index = bytecode_table.index; + let is_code = bytecode_table.is_code; + let value = bytecode_table.value; let push_rindex = meta.advice_column(); let hash_rlc = meta.advice_column(); let hash_length = meta.advice_column(); @@ -716,7 +729,14 @@ mod tests { } fn configure(meta: &mut ConstraintSystem) -> Self::Config { - Config::configure(meta, MyCircuit::r()) + let bytecode_table = BytecodeTable { + hash: meta.advice_column(), + tag: meta.advice_column(), + index: meta.advice_column(), + is_code: meta.advice_column(), + value: meta.advice_column(), + }; + Config::configure(meta, MyCircuit::r(), bytecode_table) } fn synthesize( diff --git a/zkevm-circuits/src/super_circuit.rs b/zkevm-circuits/src/super_circuit.rs index 161aa42762..ee9787e066 100644 --- a/zkevm-circuits/src/super_circuit.rs +++ b/zkevm-circuits/src/super_circuit.rs @@ -14,6 +14,10 @@ use crate::tx_circuit::{sign_verify, TxCircuit, TxCircuitConfig, TxTable}; +use crate::bytecode_circuit::bytecode_unroller::{ + BytecodeTable, Config as BytecodeConfig, UnrolledBytecode, +}; + use crate::util::Expr; use crate::{ evm_circuit::{ @@ -40,13 +44,18 @@ pub struct SuperCircuitConfig; 3], evm_circuit: EvmCircuit, tx_circuit: TxCircuitConfig, + bytecode_circuit: BytecodeConfig, } #[derive(Default)] pub struct SuperCircuit { + // EVM Circuit block: Block, fixed_table_tags: Vec, + // Tx Circuit tx_circuit: TxCircuit, + // Bytecode Circuit + bytecodes: Vec>, } impl @@ -121,6 +130,17 @@ impl Circuit value: tx_table[3], }, ), + bytecode_circuit: BytecodeConfig::configure( + meta, + power_of_randomness[0], + BytecodeTable { + hash: bytecode_table[0], + tag: bytecode_table[1], + index: bytecode_table[2], + is_code: bytecode_table[3], + value: bytecode_table[4], + }, + ), } } From 4616faf18fad6dca38b4f1579ac19254b0cbcaca Mon Sep 17 00:00:00 2001 From: Eduard S Date: Mon, 4 Jul 2022 15:44:22 +0200 Subject: [PATCH 05/26] Fix tx_circuit compat with EVM --- Cargo.lock | 16 +++- Cargo.toml | 7 +- rustfmt.toml | 1 + zkevm-circuits/src/evm_circuit.rs | 4 + zkevm-circuits/src/evm_circuit/table.rs | 32 ++++---- zkevm-circuits/src/evm_circuit/witness.rs | 4 + zkevm-circuits/src/super_circuit.rs | 97 +++++++++++++---------- zkevm-circuits/src/tx_circuit.rs | 30 ++++++- 8 files changed, 130 insertions(+), 61 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1c3c813aa9..db9dadb881 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1848,15 +1848,18 @@ checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" [[package]] name = "halo2_proofs" version = "0.1.0-beta.1" -source = "git+https://github.com/privacy-scaling-explorations/halo2.git?tag=v2022_06_03#1fc67702da729b41bfeebc9764c4c6effbd1f9ad" dependencies = [ "blake2b_simd 1.0.0", "bumpalo", "cfg-if 0.1.10", "ff 0.11.1", "group 0.11.0", + "log", + "num-bigint", + "num-integer", "pairing_bn256", "plotters", + "poseidon", "rand", "rand_core", "rayon", @@ -2893,6 +2896,17 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "poseidon" +version = "0.1.0" +source = "git+https://github.com/appliedzkp/poseidon.git?branch=circuit#1f8609776f64f36b518aac1732f18758d65a2791" +dependencies = [ + "group 0.11.0", + "pairing_bn256", + "rand", + "subtle", +] + [[package]] name = "ppv-lite86" version = "0.2.16" diff --git a/Cargo.toml b/Cargo.toml index df46afcd53..58c7caf63e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,12 @@ members = [ # and leads to a compilation error. This can be removed once the upstream PR # is resolved: https://github.com/bitvecto-rs/bitvec/pull/141 bitvec = { git = "https://github.com/ed255/bitvec.git", rev = "5cfc5fa8496c66872d21905e677120fc3e79693c" } -halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", tag = "v2022_06_03" } +# halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", tag = "v2022_06_03" } +halo2_proofs = { path = "/home/dev/git/zkevm/halo2/halo2_proofs" } + +[patch."https://github.com/privacy-scaling-explorations/halo2"] +# halo2_proofs = { git = "https://github.com/han0110/halo2", branch = "feature/abstraction-experiment", package = "halo2_proofs" } +halo2_proofs = { path = "/home/dev/git/zkevm/halo2/halo2_proofs" } # Definition of benchmarks profile to use. [profile.bench] diff --git a/rustfmt.toml b/rustfmt.toml index 22f8bbbcbe..6171f88c92 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,3 +1,4 @@ max_width = 100 wrap_comments = true +normalize_comments = false edition = "2021" diff --git a/zkevm-circuits/src/evm_circuit.rs b/zkevm-circuits/src/evm_circuit.rs index 9e923b81b1..2daadb79c0 100644 --- a/zkevm-circuits/src/evm_circuit.rs +++ b/zkevm-circuits/src/evm_circuit.rs @@ -164,9 +164,12 @@ pub fn load_txs( } offset += 1; + // println!("DBG load_txs"); for tx in txs.iter() { for row in tx.table_assignments(randomness) { + // print!("{:02} ", offset); for (column, value) in tx_table.iter().zip_eq(row) { + // print!("{:?} ", value); region.assign_advice( || format!("tx table row {}", offset), *column, @@ -175,6 +178,7 @@ pub fn load_txs( )?; } offset += 1; + // println!(""); } } Ok(()) diff --git a/zkevm-circuits/src/evm_circuit/table.rs b/zkevm-circuits/src/evm_circuit/table.rs index 80d7429f3f..c4325bee50 100644 --- a/zkevm-circuits/src/evm_circuit/table.rs +++ b/zkevm-circuits/src/evm_circuit/table.rs @@ -1,4 +1,6 @@ -use crate::{evm_circuit::step::ExecutionState, impl_expr}; +use crate::evm_circuit::step::ExecutionState; +use crate::impl_expr; +pub use crate::tx_circuit::TxFieldTag as TxContextFieldTag; use halo2_proofs::{ arithmetic::FieldExt, plonk::{Advice, Column, Expression, Fixed, VirtualCells}, @@ -115,19 +117,19 @@ impl FixedTableTag { } } -#[derive(Clone, Copy, Debug)] -pub enum TxContextFieldTag { - Nonce = 1, - Gas, - GasPrice, - CallerAddress, - CalleeAddress, - IsCreate, - Value, - CallDataLength, - CallDataGasCost, - CallData, -} +// #[derive(Clone, Copy, Debug)] +// pub enum TxContextFieldTag { +// Nonce = 1, +// Gas, +// GasPrice, +// CallerAddress, +// CalleeAddress, +// IsCreate, +// Value, +// CallDataLength, +// CallDataGasCost, +// CallData, +// } // Keep the sequence consistent with OpcodeId for scalar #[derive(Clone, Copy, Debug)] @@ -238,7 +240,7 @@ pub enum CallContextFieldTag { } impl_expr!(FixedTableTag); -impl_expr!(TxContextFieldTag); +// impl_expr!(TxContextFieldTag); impl_expr!(RwTableTag); impl_expr!(AccountFieldTag); impl_expr!(BytecodeFieldTag); diff --git a/zkevm-circuits/src/evm_circuit/witness.rs b/zkevm-circuits/src/evm_circuit/witness.rs index 97b1a411cd..83a0d6a946 100644 --- a/zkevm-circuits/src/evm_circuit/witness.rs +++ b/zkevm-circuits/src/evm_circuit/witness.rs @@ -1246,6 +1246,10 @@ impl From<&circuit_input_builder::ExecStep> for ExecutionState { OpcodeId::DIFFICULTY | OpcodeId::BASEFEE => ExecutionState::BLOCKCTXU256, OpcodeId::GAS => ExecutionState::GAS, OpcodeId::SELFBALANCE => ExecutionState::SELFBALANCE, + OpcodeId::SHA3 => { + log::warn!("ExecutionState::SHA3 is implemented with DummyGadget"); + ExecutionState::SHA3 + } OpcodeId::SHR => ExecutionState::SHR, OpcodeId::SLOAD => ExecutionState::SLOAD, OpcodeId::SSTORE => ExecutionState::SSTORE, diff --git a/zkevm-circuits/src/super_circuit.rs b/zkevm-circuits/src/super_circuit.rs index ee9787e066..7dee374e25 100644 --- a/zkevm-circuits/src/super_circuit.rs +++ b/zkevm-circuits/src/super_circuit.rs @@ -23,7 +23,7 @@ use crate::{ evm_circuit::{ table::FixedTableTag, witness::Block, - EvmCircuit, {load_block, load_bytecodes, load_rws}, + EvmCircuit, {load_block, load_bytecodes, load_rws, load_txs}, }, rw_table::RwTable, }; @@ -44,7 +44,7 @@ pub struct SuperCircuitConfig; 3], evm_circuit: EvmCircuit, tx_circuit: TxCircuitConfig, - bytecode_circuit: BytecodeConfig, + // bytecode_circuit: BytecodeConfig, // TODO } #[derive(Default)] @@ -54,8 +54,8 @@ pub struct SuperCircuit, // Tx Circuit tx_circuit: TxCircuit, - // Bytecode Circuit - bytecodes: Vec>, + /* Bytecode Circuit + * bytecodes: Vec>, // TODO */ } impl @@ -130,6 +130,7 @@ impl Circuit value: tx_table[3], }, ), + /* bytecode_circuit: BytecodeConfig::configure( meta, power_of_randomness[0], @@ -141,6 +142,7 @@ impl Circuit value: bytecode_table[4], }, ), + */ } } @@ -153,12 +155,12 @@ impl Circuit .evm_circuit .load_fixed_table(&mut layouter, self.fixed_table_tags.clone())?; config.evm_circuit.load_byte_table(&mut layouter)?; - // load_txs( - // &config.tx_table, - // &mut layouter, - // &self.block.txs, - // self.block.randomness, - // )?; + load_txs( + &config.tx_table, + &mut layouter, + &self.block.txs, + self.block.randomness, + )?; load_rws( &config.rw_table, &mut layouter, @@ -184,38 +186,42 @@ impl Circuit Ok(()) } } -use eth_types::{Address, U64}; -use ethers_core::{types::TransactionRequest, utils::keccak256}; -use ethers_signers::LocalWallet; -use std::collections::HashMap; - -// Testing function -pub fn sign_txs( - txs: &mut [eth_types::Transaction], - chain_id: u64, - wallets: &HashMap, -) { - for tx in txs.iter_mut() { - let wallet = wallets.get(&tx.from).unwrap(); - let req = TransactionRequest::new() - .from(tx.from) - .to(tx.to.unwrap()) - .nonce(tx.nonce) - .value(tx.value) - .data(tx.input.clone()) - .gas(tx.gas) - .gas_price(tx.gas_price.unwrap()); - let tx_rlp = req.rlp(chain_id); - let sighash = keccak256(tx_rlp.as_ref()).into(); - let sig = wallet.sign_hash(sighash, true); - tx.v = U64::from(sig.v); - tx.r = sig.r; - tx.s = sig.s; + +#[cfg(test)] +pub mod test { + use eth_types::{Address, U64}; + use ethers_core::{types::TransactionRequest, utils::keccak256}; + use ethers_signers::LocalWallet; + use std::collections::HashMap; + // Testing function + pub fn sign_txs( + txs: &mut [eth_types::Transaction], + chain_id: u64, + wallets: &HashMap, + ) { + for tx in txs.iter_mut() { + let wallet = wallets.get(&tx.from).unwrap(); + let req = TransactionRequest::new() + .from(tx.from) + .to(tx.to.unwrap()) + .nonce(tx.nonce) + .value(tx.value) + .data(tx.input.clone()) + .gas(tx.gas) + .gas_price(tx.gas_price.unwrap()); + let tx_rlp = req.rlp(chain_id); + let sighash = keccak256(tx_rlp.as_ref()).into(); + let sig = wallet.sign_hash(sighash, true); + tx.v = U64::from(sig.v); + tx.r = sig.r; + tx.s = sig.s; + } } } #[cfg(test)] mod super_circuit_tests { + use super::test::*; use super::*; use crate::{ evm_circuit::witness::block_convert, @@ -230,11 +236,12 @@ mod super_circuit_tests { }; use ethers_signers::{LocalWallet, Signer}; use group::{Curve, Group}; - use halo2_proofs::dev::{MockProver, VerifyFailure}; + use halo2_proofs::dev::{MockProver, VerifyConfig, VerifyFailure}; use mock::{TestContext, MOCK_CHAIN_ID}; use rand::SeedableRng; use rand_chacha::ChaCha20Rng; use secp256k1::Secp256k1Affine; + use std::collections::HashMap; use strum::IntoEnumIterator; struct Inputs { @@ -289,7 +296,12 @@ mod super_circuit_tests { tx_circuit, }; let prover = MockProver::::run(k, &circuit, instance).unwrap(); - prover.verify() + prover.verify_par(VerifyConfig { + selectors: true, + gates: true, + lookups: true, + perms: true, + }) } fn run_test_circuit_complete_fixed_table( @@ -365,6 +377,11 @@ mod super_circuit_tests { aux_generator, }; - assert_eq!(run_test_circuit_complete_fixed_table(inputs), Ok(())); + let res = run_test_circuit_complete_fixed_table(inputs); + if let Err(err) = res { + eprintln!("Verification failures:"); + eprintln!("{:#?}", err); + panic!("Failed verification"); + } } } diff --git a/zkevm-circuits/src/tx_circuit.rs b/zkevm-circuits/src/tx_circuit.rs index f850e2646b..a7d9e219da 100644 --- a/zkevm-circuits/src/tx_circuit.rs +++ b/zkevm-circuits/src/tx_circuit.rs @@ -4,8 +4,11 @@ // - *_be: Big-Endian bytes // - *_le: Little-Endian bytes +#![allow(missing_docs)] + pub mod sign_verify; +use crate::impl_expr; use crate::util::{random_linear_combine_word as rlc, Expr}; use eth_types::{ geth_types::Transaction, Address, Field, ToBigEndian, ToLittleEndian, ToScalar, Word, @@ -160,6 +163,8 @@ pub enum TxFieldTag { Value, /// CallDataLength CallDataLength, + /// Gas cost for transaction call data (4 for byte == 0, 16 otherwise) + CallDataGasCost, /// TxSignHash: Hash of the transaction without the signature, used for /// signing. TxSignHash, @@ -167,6 +172,8 @@ pub enum TxFieldTag { CallData, } +impl_expr!(TxFieldTag); + /// Config for TxCircuit #[derive(Clone, Debug)] pub struct TxCircuitConfig { @@ -327,15 +334,13 @@ impl let address_cell = assigned_sig_verif.address.cell(); let msg_hash_rlc_cell = assigned_sig_verif.msg_hash_rlc.cell(); let msg_hash_rlc_value = assigned_sig_verif.msg_hash_rlc.value(); + // println!("DBG tx_circuit.assign"); for (tag, value) in &[ ( TxFieldTag::Nonce, rlc(tx.nonce.to_le_bytes(), self.randomness), ), - ( - TxFieldTag::Gas, - rlc(tx.gas_limit.to_le_bytes(), self.randomness), - ), + (TxFieldTag::Gas, F::from(tx.gas_limit.as_u64())), ( TxFieldTag::GasPrice, rlc(tx.gas_price.to_le_bytes(), self.randomness), @@ -360,6 +365,15 @@ impl TxFieldTag::CallDataLength, F::from(tx.call_data.0.len() as u64), ), + ( + TxFieldTag::CallDataGasCost, + F::from( + tx.call_data + .0 + .iter() + .fold(0, |acc, byte| acc + if *byte == 0 { 4 } else { 16 }), + ), + ), ( TxFieldTag::TxSignHash, *msg_hash_rlc_value.unwrap_or(&F::zero()), @@ -367,6 +381,14 @@ impl ] { let assigned_cell = config.assign_row(&mut region, offset, i + 1, *tag, 0, *value)?; + // println!( + // "{:02} {:?} {:?} {:?} {:?}", + // offset, + // i + 1, + // *tag as u64, + // 0, + // *value + // ); offset += 1; // Ref. spec 0. Copy constraints using fixed offsets between the tx rows and From 23fc15817a981c7ba682b8cb37fad207d7c6824a Mon Sep 17 00:00:00 2001 From: Eduard S Date: Mon, 4 Jul 2022 17:43:18 +0200 Subject: [PATCH 06/26] Add bytecode circuit to super circuit --- Cargo.toml | 8 +- .../src/bytecode_circuit/bytecode_unroller.rs | 207 +++++++++++------- zkevm-circuits/src/evm_circuit.rs | 6 + zkevm-circuits/src/super_circuit.rs | 61 ++++-- zkevm-circuits/src/tx_circuit.rs | 19 +- 5 files changed, 187 insertions(+), 114 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 58c7caf63e..d4e1b060dd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,11 +20,11 @@ members = [ # is resolved: https://github.com/bitvecto-rs/bitvec/pull/141 bitvec = { git = "https://github.com/ed255/bitvec.git", rev = "5cfc5fa8496c66872d21905e677120fc3e79693c" } # halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", tag = "v2022_06_03" } -halo2_proofs = { path = "/home/dev/git/zkevm/halo2/halo2_proofs" } +halo2_proofs = { path = "../halo2/halo2_proofs" } [patch."https://github.com/privacy-scaling-explorations/halo2"] # halo2_proofs = { git = "https://github.com/han0110/halo2", branch = "feature/abstraction-experiment", package = "halo2_proofs" } -halo2_proofs = { path = "/home/dev/git/zkevm/halo2/halo2_proofs" } +halo2_proofs = { path = "../halo2/halo2_proofs" } # Definition of benchmarks profile to use. [profile.bench] @@ -43,5 +43,5 @@ debug = false debug-assertions = true overflow-checks = true rpath = false -lto = "thin" -incremental = false +# lto = "thin" +# incremental = false diff --git a/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs b/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs index 611fb4c923..5198458eee 100644 --- a/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs +++ b/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs @@ -36,23 +36,23 @@ pub(crate) struct BytecodeRow { /// Unrolled bytecode #[derive(Clone, Debug, PartialEq)] -pub(crate) struct UnrolledBytecode { +pub struct UnrolledBytecode { bytes: Vec, rows: Vec>, } #[derive(Clone, Debug)] pub struct BytecodeTable { - hash: Column, - tag: Column, - index: Column, - is_code: Column, - value: Column, + pub hash: Column, + pub tag: Column, + pub index: Column, + pub is_code: Column, + pub value: Column, } #[derive(Clone, Debug)] pub struct Config { - r: F, // TODO: Replace by Expression + randomness: Expression, minimum_rows: usize, q_enable: Column, q_first: Column, @@ -79,7 +79,7 @@ pub struct Config { impl Config { pub(crate) fn configure( meta: &mut ConstraintSystem, - r: F, + randomness: Expression, bytecode_table: BytecodeTable, ) -> Self { let q_enable = meta.fixed_column(); @@ -180,9 +180,9 @@ impl Config { ), ); cb.require_equal( - "hash_rlc := hash_rlc_prev * r + byte", + "hash_rlc := hash_rlc_prev * randomness + byte", meta.query_advice(hash_rlc, Rotation::cur()), - meta.query_advice(hash_rlc, Rotation::prev()) * r + meta.query_advice(hash_rlc, Rotation::prev()) * randomness.clone() + meta.query_advice(value, Rotation::cur()), ); cb.require_equal( @@ -229,13 +229,16 @@ impl Config { meta.query_advice(value, Rotation::cur()), meta.query_advice(hash_length, Rotation::cur()), ); - cb.condition(length_is_zero.clone().is_zero_expression, |cb| { - cb.require_equal( - "if length == 0: hash == RLC(EMPTY_HASH, randomness)", - meta.query_advice(hash, Rotation::cur()), - Expression::Constant(keccak(&[], r)), - ); - }); + // FIXME: Since randomness is only known at synthesis time, the RLC of empty + // hash is not constant. Consider doing a lookup to the empty hash + // value? cb.condition(length_is_zero.clone().is_zero_expression, + // |cb| { cb.require_equal( + // "if length == 0: hash == RLC(EMPTY_HASH, randomness)", + // meta.query_advice(hash, Rotation::cur()), + // Expression::Constant(keccak(&[], randomness)), + // ); + // }); + // Conditions: // - Not Continuing // - This is the start of a new bytecode @@ -379,7 +382,7 @@ impl Config { }); Config { - r, + randomness, minimum_rows: meta.minimum_rows(), q_enable, q_first, @@ -406,9 +409,10 @@ impl Config { pub(crate) fn assign( &self, - mut layouter: impl Layouter, + layouter: &mut impl Layouter, size: usize, witness: &[UnrolledBytecode], + randomness: F, ) -> Result<(), Error> { let push_rindex_is_zero_chip = IsZeroChip::construct(self.push_rindex_is_zero.clone()); let length_is_zero_chip = IsZeroChip::construct(self.length_is_zero.clone()); @@ -439,7 +443,7 @@ impl Config { } else { push_rindex - 1 }; - hash_rlc = hash_rlc * self.r + row.value; + hash_rlc = hash_rlc * randomness + row.value; } // Set the data for this row @@ -577,6 +581,7 @@ impl Config { &self, layouter: &mut impl Layouter, bytecodes: &[UnrolledBytecode], + randomness: F, ) -> Result<(), Error> { // push table: BYTE -> NUM_PUSHED: // [0, OpcodeId::PUSH1[ -> 0 @@ -608,8 +613,8 @@ impl Config { || "keccak table", |mut region| { for (offset, bytecode) in bytecodes.iter().map(|v| v.bytes.clone()).enumerate() { - let hash: F = keccak(&bytecode[..], self.r); - let rlc: F = linear_combine(bytecode.clone(), self.r); + let hash: F = keccak(&bytecode[..], randomness); + let rlc: F = linear_combine(bytecode.clone(), randomness); let size = F::from(bytecode.len() as u64); for (name, column, value) in &[ ("rlc", self.keccak_table[0], rlc), @@ -631,8 +636,8 @@ impl Config { } } -fn unroll(bytes: Vec, r: F) -> UnrolledBytecode { - let hash = keccak(&bytes[..], r); +pub fn unroll(bytes: Vec, randomness: F) -> UnrolledBytecode { + let hash = keccak(&bytes[..], randomness); let mut rows = vec![BytecodeRow:: { hash, tag: F::from(BytecodeFieldTag::Length as u64), @@ -674,10 +679,13 @@ fn get_push_size(byte: u8) -> u64 { } } -fn keccak(msg: &[u8], r: F) -> F { +fn keccak(msg: &[u8], randomness: F) -> F { let mut keccak = Keccak::default(); keccak.update(msg); - RandomLinearCombination::::random_linear_combine(keccak.digest().try_into().unwrap(), r) + RandomLinearCombination::::random_linear_combine( + keccak.digest().try_into().unwrap(), + randomness, + ) } fn into_words(message: &[u8]) -> Vec { @@ -693,8 +701,8 @@ fn into_words(message: &[u8]) -> Vec { words } -fn linear_combine(bytes: Vec, r: F) -> F { - encode(bytes.into_iter(), r) +fn linear_combine(bytes: Vec, randomness: F) -> F { + encode(bytes.into_iter(), randomness) } #[cfg(test)] @@ -712,12 +720,16 @@ mod tests { struct MyCircuit { bytecodes: Vec>, size: usize, + randomness: F, } - impl MyCircuit { - fn r() -> F { - F::from(123456) - } + // impl MyCircuit { + // fn randomness() -> F { + // F::from(123456) + // } + // } + fn get_randomness() -> F { + F::from(123456) } impl Circuit for MyCircuit { @@ -736,7 +748,24 @@ mod tests { is_code: meta.advice_column(), value: meta.advice_column(), }; - Config::configure(meta, MyCircuit::r(), bytecode_table) + + // This gate is used just to get the array of expressions from the power of + // randomness instance column, so that later on we don't need to query + // columns everywhere, and can pass the power of randomness array + // expression everywhere. The gate itself doesn't add any constraints. + let randomness = { + let column = meta.instance_column(); + let mut randomness = None; + + meta.create_gate("", |meta| { + randomness = Some(meta.query_instance(column, Rotation::cur())); + [0.expr()] + }); + + randomness.unwrap() + }; + + Config::configure(meta, randomness, bytecode_table) } fn synthesize( @@ -744,16 +773,17 @@ mod tests { config: Self::Config, mut layouter: impl Layouter, ) -> Result<(), Error> { - config.load(&mut layouter, &self.bytecodes)?; - config.assign(layouter, self.size, &self.bytecodes)?; + config.load(&mut layouter, &self.bytecodes, self.randomness)?; + config.assign(&mut layouter, self.size, &self.bytecodes, self.randomness)?; Ok(()) } } - fn verify(k: u32, bytecodes: Vec>, success: bool) { + fn verify(k: u32, bytecodes: Vec>, randomness: F, success: bool) { let circuit = MyCircuit:: { bytecodes, size: 2usize.pow(k), + randomness, }; let prover = MockProver::::run(k, &circuit, vec![]).unwrap(); @@ -774,7 +804,7 @@ mod tests { #[test] fn bytecode_unrolling() { let k = 10; - let r = MyCircuit::r(); + let randomness = get_randomness(); let mut rows = vec![]; let mut bytecode = Bytecode::default(); // First add all non-push bytes, which should all be seen as code @@ -812,7 +842,7 @@ mod tests { } } // Set the hash of the complete bytecode in the rows - let hash = keccak(&bytecode.to_vec()[..], r); + let hash = keccak(&bytecode.to_vec()[..], randomness); for row in rows.iter_mut() { row.hash = hash; } @@ -827,7 +857,7 @@ mod tests { }, ); // Unroll the bytecode - let unrolled = unroll(bytecode.to_vec(), r); + let unrolled = unroll(bytecode.to_vec(), randomness); // Check if the bytecode was unrolled correctly assert_eq!( UnrolledBytecode { @@ -837,66 +867,83 @@ mod tests { unrolled, ); // Verify the unrolling in the circuit - verify::(k, vec![unrolled], true); + verify::(k, vec![unrolled], randomness, true); } /// Tests a fully empty circuit #[test] fn bytecode_empty() { let k = 9; - let r = MyCircuit::r(); - verify::(k, vec![unroll(vec![], r)], true); + let randomness = get_randomness(); + verify::(k, vec![unroll(vec![], randomness)], randomness, true); } #[test] fn bytecode_simple() { let k = 9; - let r = MyCircuit::r(); + let randomness = get_randomness(); let bytecodes = vec![ - unroll(vec![7u8], r), - unroll(vec![6u8], r), - unroll(vec![5u8], r), + unroll(vec![7u8], randomness), + unroll(vec![6u8], randomness), + unroll(vec![5u8], randomness), ]; - verify::(k, bytecodes, true); + verify::(k, bytecodes, randomness, true); } /// Tests a fully full circuit #[test] fn bytecode_full() { let k = 9; - let r = MyCircuit::r(); - verify::(k, vec![unroll(vec![7u8; 2usize.pow(k) - 7], r)], true); + let randomness = get_randomness(); + verify::( + k, + vec![unroll(vec![7u8; 2usize.pow(k) - 7], randomness)], + randomness, + true, + ); } /// Tests a circuit with incomplete bytecode #[test] fn bytecode_incomplete() { let k = 9; - let r = MyCircuit::r(); - verify::(k, vec![unroll(vec![7u8; 2usize.pow(k) + 1], r)], false); + let randomness = get_randomness(); + verify::( + k, + vec![unroll(vec![7u8; 2usize.pow(k) + 1], randomness)], + randomness, + false, + ); } /// Tests multiple bytecodes in a single circuit #[test] fn bytecode_push() { let k = 9; - let r = MyCircuit::r(); + let randomness = get_randomness(); verify::( k, vec![ - unroll(vec![], r), - unroll(vec![OpcodeId::PUSH32.as_u8()], r), - unroll(vec![OpcodeId::PUSH32.as_u8(), OpcodeId::ADD.as_u8()], r), - unroll(vec![OpcodeId::ADD.as_u8(), OpcodeId::PUSH32.as_u8()], r), + unroll(vec![], randomness), + unroll(vec![OpcodeId::PUSH32.as_u8()], randomness), + unroll( + vec![OpcodeId::PUSH32.as_u8(), OpcodeId::ADD.as_u8()], + randomness, + ), + unroll( + vec![OpcodeId::ADD.as_u8(), OpcodeId::PUSH32.as_u8()], + randomness, + ), unroll( vec![ OpcodeId::ADD.as_u8(), OpcodeId::PUSH32.as_u8(), OpcodeId::ADD.as_u8(), ], - r, + randomness, ), ], + randomness, true, ); } @@ -905,21 +952,21 @@ mod tests { #[test] fn bytecode_invalid_hash_data() { let k = 9; - let r = MyCircuit::r(); + let randomness = get_randomness(); let bytecode = vec![8u8, 2, 3, 8, 9, 7, 128]; - let unrolled = unroll(bytecode, r); - verify::(k, vec![unrolled.clone()], true); + let unrolled = unroll(bytecode, randomness); + verify::(k, vec![unrolled.clone()], randomness, true); // Change the hash on the first position { let mut invalid = unrolled.clone(); invalid.rows[0].hash += Fr::from(1u64); - verify::(k, vec![invalid], false); + verify::(k, vec![invalid], randomness, false); } // Change the hash on another position { let mut invalid = unrolled.clone(); invalid.rows[4].hash += Fr::from(1u64); - verify::(k, vec![invalid], false); + verify::(k, vec![invalid], randomness, false); } // Change all the hashes so it doesn't match the keccak lookup hash { @@ -927,7 +974,7 @@ mod tests { for row in invalid.rows.iter_mut() { row.hash = Fr::one(); } - verify::(k, vec![invalid], false); + verify::(k, vec![invalid], randomness, false); } } @@ -936,23 +983,23 @@ mod tests { #[ignore] fn bytecode_invalid_index() { let k = 9; - let r = MyCircuit::r(); + let randomness = get_randomness(); let bytecode = vec![8u8, 2, 3, 8, 9, 7, 128]; - let unrolled = unroll(bytecode, r); - verify::(k, vec![unrolled.clone()], true); + let unrolled = unroll(bytecode, randomness); + verify::(k, vec![unrolled.clone()], randomness, true); // Start the index at 1 { let mut invalid = unrolled.clone(); for row in invalid.rows.iter_mut() { row.index += Fr::one(); } - verify::(k, vec![invalid], false); + verify::(k, vec![invalid], randomness, false); } // Don't increment an index once { let mut invalid = unrolled; invalid.rows.last_mut().unwrap().index -= Fr::one(); - verify::(k, vec![invalid], false); + verify::(k, vec![invalid], randomness, false); } } @@ -960,27 +1007,27 @@ mod tests { #[test] fn bytecode_invalid_byte_data() { let k = 9; - let r = MyCircuit::r(); + let randomness = get_randomness(); let bytecode = vec![8u8, 2, 3, 8, 9, 7, 128]; - let unrolled = unroll(bytecode, r); - verify::(k, vec![unrolled.clone()], true); + let unrolled = unroll(bytecode, randomness); + verify::(k, vec![unrolled.clone()], randomness, true); // Change the first byte { let mut invalid = unrolled.clone(); invalid.rows[1].value = Fr::from(9u64); - verify::(k, vec![invalid], false); + verify::(k, vec![invalid], randomness, false); } // Change a byte on another position { let mut invalid = unrolled.clone(); invalid.rows[5].value = Fr::from(6u64); - verify::(k, vec![invalid], false); + verify::(k, vec![invalid], randomness, false); } // Set a byte value out of range { let mut invalid = unrolled; invalid.rows[3].value = Fr::from(256u64); - verify::(k, vec![invalid], false); + verify::(k, vec![invalid], randomness, false); } } @@ -988,7 +1035,7 @@ mod tests { #[test] fn bytecode_invalid_is_code() { let k = 9; - let r = MyCircuit::r(); + let randomness = get_randomness(); let bytecode = vec![ OpcodeId::ADD.as_u8(), OpcodeId::PUSH1.as_u8(), @@ -998,25 +1045,25 @@ mod tests { OpcodeId::ADD.as_u8(), OpcodeId::PUSH6.as_u8(), ]; - let unrolled = unroll(bytecode, r); - verify::(k, vec![unrolled.clone()], true); + let unrolled = unroll(bytecode, randomness); + verify::(k, vec![unrolled.clone()], randomness, true); // Mark the 3rd byte as code (is push data from the first PUSH1) { let mut invalid = unrolled.clone(); invalid.rows[3].is_code = Fr::one(); - verify::(k, vec![invalid], false); + verify::(k, vec![invalid], randomness, false); } // Mark the 4rd byte as data (is code) { let mut invalid = unrolled.clone(); invalid.rows[4].is_code = Fr::zero(); - verify::(k, vec![invalid], false); + verify::(k, vec![invalid], randomness, false); } // Mark the 7th byte as code (is data for the PUSH7) { let mut invalid = unrolled; invalid.rows[7].is_code = Fr::one(); - verify::(k, vec![invalid], false); + verify::(k, vec![invalid], randomness, false); } } } diff --git a/zkevm-circuits/src/evm_circuit.rs b/zkevm-circuits/src/evm_circuit.rs index 2daadb79c0..0bf361859b 100644 --- a/zkevm-circuits/src/evm_circuit.rs +++ b/zkevm-circuits/src/evm_circuit.rs @@ -144,6 +144,12 @@ use crate::{ rw_table::RwTable, }; +// TODO: Define a table type for each table, kept in an upper level crate. + +// TODO: Move these load functions to each specific circuit, and import them +// into the EVM circuit. These functions look really clean, so maybe we can +// replace the specific circuit loader by these? + pub fn load_txs( tx_table: &[Column; 4], layouter: &mut impl Layouter, diff --git a/zkevm-circuits/src/super_circuit.rs b/zkevm-circuits/src/super_circuit.rs index 7dee374e25..64cfb9ccc3 100644 --- a/zkevm-circuits/src/super_circuit.rs +++ b/zkevm-circuits/src/super_circuit.rs @@ -15,7 +15,7 @@ use crate::tx_circuit::{sign_verify, TxCircuit, TxCircuitConfig, TxTable}; use crate::bytecode_circuit::bytecode_unroller::{ - BytecodeTable, Config as BytecodeConfig, UnrolledBytecode, + unroll, BytecodeTable, Config as BytecodeConfig, UnrolledBytecode, }; use crate::util::Expr; @@ -44,7 +44,7 @@ pub struct SuperCircuitConfig; 3], evm_circuit: EvmCircuit, tx_circuit: TxCircuitConfig, - // bytecode_circuit: BytecodeConfig, // TODO + bytecode_circuit: BytecodeConfig, } #[derive(Default)] @@ -54,8 +54,9 @@ pub struct SuperCircuit, // Tx Circuit tx_circuit: TxCircuit, - /* Bytecode Circuit - * bytecodes: Vec>, // TODO */ + // Bytecode Circuit + // bytecodes: Vec>, + bytecode_size: usize, } impl @@ -122,7 +123,7 @@ impl Circuit ), tx_circuit: TxCircuitConfig::new( meta, - power_of_randomness, + power_of_randomness.clone(), TxTable { tx_id: tx_table[0], tag: tx_table[1], @@ -130,10 +131,9 @@ impl Circuit value: tx_table[3], }, ), - /* bytecode_circuit: BytecodeConfig::configure( meta, - power_of_randomness[0], + power_of_randomness[0].clone(), BytecodeTable { hash: bytecode_table[0], tag: bytecode_table[1], @@ -142,7 +142,6 @@ impl Circuit value: bytecode_table[4], }, ), - */ } } @@ -151,28 +150,29 @@ impl Circuit config: Self::Config, mut layouter: impl Layouter, ) -> Result<(), Error> { + // --- EVM Circuit --- config .evm_circuit .load_fixed_table(&mut layouter, self.fixed_table_tags.clone())?; config.evm_circuit.load_byte_table(&mut layouter)?; - load_txs( - &config.tx_table, - &mut layouter, - &self.block.txs, - self.block.randomness, - )?; + // load_txs( + // &config.tx_table, + // &mut layouter, + // &self.block.txs, + // self.block.randomness, + // )?; load_rws( &config.rw_table, &mut layouter, &self.block.rws, self.block.randomness, )?; - load_bytecodes( - &config.bytecode_table, - &mut layouter, - &self.block.bytecodes, - self.block.randomness, - )?; + // load_bytecodes( + // &config.bytecode_table, + // &mut layouter, + // &self.block.bytecodes, + // self.block.randomness, + // )?; load_block( &config.block_table, &mut layouter, @@ -182,7 +182,24 @@ impl Circuit config .evm_circuit .assign_block_exact(&mut layouter, &self.block)?; - self.tx_circuit.synthesize(config.tx_circuit, layouter)?; + // --- Tx Circuit --- + self.tx_circuit.assign(config.tx_circuit, &mut layouter)?; + // -- Bytecode Circuit --- + let bytecodes: Vec> = self + .block + .bytecodes + .iter() + .map(|b| unroll(b.bytes.clone(), self.block.randomness)) + .collect(); + config + .bytecode_circuit + .load(&mut layouter, &bytecodes, self.block.randomness)?; + config.bytecode_circuit.assign( + &mut layouter, + self.bytecode_size, + &bytecodes, + self.block.randomness, + )?; Ok(()) } } @@ -294,6 +311,8 @@ mod super_circuit_tests { block, fixed_table_tags, tx_circuit, + // bytecodes, + bytecode_size: 2usize.pow(k), }; let prover = MockProver::::run(k, &circuit, instance).unwrap(); prover.verify_par(VerifyConfig { diff --git a/zkevm-circuits/src/tx_circuit.rs b/zkevm-circuits/src/tx_circuit.rs index a7d9e219da..7b10070b3a 100644 --- a/zkevm-circuits/src/tx_circuit.rs +++ b/zkevm-circuits/src/tx_circuit.rs @@ -295,7 +295,7 @@ impl pub fn assign( &self, config: TxCircuitConfig, - mut layouter: impl Layouter, + layouter: &mut impl Layouter, ) -> Result<(), Error> { assert!(self.txs.len() <= MAX_TXS); let sign_datas: Vec = self @@ -308,12 +308,9 @@ impl }) }) .try_collect()?; - let assigned_sig_verifs = self.sign_verify.assign( - &config.sign_verify, - &mut layouter, - self.randomness, - &sign_datas, - )?; + let assigned_sig_verifs = + self.sign_verify + .assign(&config.sign_verify, layouter, self.randomness, &sign_datas)?; layouter.assign_region( || "tx table", @@ -479,8 +476,12 @@ impl Circuit TxCircuitConfig::new(meta, power_of_randomness, tx_table) } - fn synthesize(&self, config: Self::Config, layouter: impl Layouter) -> Result<(), Error> { - self.assign(config, layouter) + fn synthesize( + &self, + config: Self::Config, + mut layouter: impl Layouter, + ) -> Result<(), Error> { + self.assign(config, &mut layouter) } } From 396c466ae05510d776eca66847805ca23c1601bb Mon Sep 17 00:00:00 2001 From: Eduard S Date: Mon, 11 Jul 2022 12:10:52 +0200 Subject: [PATCH 07/26] WIP --- zkevm-circuits/src/super_circuit.rs | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/zkevm-circuits/src/super_circuit.rs b/zkevm-circuits/src/super_circuit.rs index 64cfb9ccc3..d17313f587 100644 --- a/zkevm-circuits/src/super_circuit.rs +++ b/zkevm-circuits/src/super_circuit.rs @@ -184,7 +184,7 @@ impl Circuit .assign_block_exact(&mut layouter, &self.block)?; // --- Tx Circuit --- self.tx_circuit.assign(config.tx_circuit, &mut layouter)?; - // -- Bytecode Circuit --- + // --- Bytecode Circuit --- let bytecodes: Vec> = self .block .bytecodes @@ -288,13 +288,12 @@ mod super_circuit_tests { .map(|tag| tag.build::().count()) .sum::(), ); - let k = k.max(log2_ceil( - 64 + block - .bytecodes - .iter() - .map(|bytecode| bytecode.bytes.len()) - .sum::(), - )); + let bytecodes_len = block + .bytecodes + .iter() + .map(|bytecode| bytecode.bytes.len()) + .sum::(); + let k = k.max(log2_ceil(64 + bytecodes_len)); let k = k.max(log2_ceil(64 + num_rows_required_for_steps)); let k = k + 1; log::debug!("evm circuit uses k = {}", k); @@ -311,8 +310,8 @@ mod super_circuit_tests { block, fixed_table_tags, tx_circuit, - // bytecodes, - bytecode_size: 2usize.pow(k), + // bytecode_size: 2usize.pow(k), + bytecode_size: bytecodes_len + 64, }; let prover = MockProver::::run(k, &circuit, instance).unwrap(); prover.verify_par(VerifyConfig { From 77437849baebbf4102413c65e0113721172bc2b9 Mon Sep 17 00:00:00 2001 From: Eduard S Date: Tue, 12 Jul 2022 15:45:39 +0200 Subject: [PATCH 08/26] Fix bytecode assignment --- .../src/bytecode_circuit/bytecode_unroller.rs | 21 +++++- zkevm-circuits/src/evm_circuit.rs | 9 +++ zkevm-circuits/src/super_circuit.rs | 5 +- zkevm-circuits/src/util.rs | 65 +++++++++++++++++++ 4 files changed, 97 insertions(+), 3 deletions(-) diff --git a/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs b/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs index 5198458eee..ed2a3c648d 100644 --- a/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs +++ b/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs @@ -9,7 +9,7 @@ use crate::{ util::Expr, }; use bus_mapping::evm::OpcodeId; -use eth_types::Field; +use eth_types::{Field, ToLittleEndian, Word}; use gadgets::{ evm_word::encode, is_zero::{IsZeroChip, IsZeroConfig, IsZeroInstruction}, @@ -22,6 +22,8 @@ use halo2_proofs::{ use keccak256::plain::Keccak; use std::{convert::TryInto, vec}; +// use crate::util::TableShow; + use super::param::{KECCAK_WIDTH, PUSH_TABLE_WIDTH}; /// Public data for the bytecode @@ -425,6 +427,9 @@ impl Config { |mut region| { let mut offset = 0; let mut push_rindex_prev = 0; + println!("> BytecodeConfig::assign"); + // let mut table = + // TableShow::::new(vec!["codeHash", "tag", "index", "isCode", "value"]); for bytecode in witness.iter() { // Run over all the bytes @@ -470,6 +475,11 @@ impl Config { )?; push_rindex_prev = push_rindex; offset += 1; + // table.push(0, row.hash); + // table.push(1, row.tag); + // table.push(2, row.index); + // table.push(3, row.is_code); + // table.push(4, row.value); } } } @@ -497,7 +507,13 @@ impl Config { F::from(push_rindex_prev), )?; push_rindex_prev = 0; + // table.push(0, F::zero()); + // table.push(1, F::from(BytecodeFieldTag::Padding as u64)); + // table.push(2, F::zero()); + // table.push(3, F::one()); + // table.push(4, F::zero()); } + // table.print(); Ok(()) }, ) @@ -577,6 +593,7 @@ impl Config { Ok(()) } + /// load tables pub(crate) fn load( &self, layouter: &mut impl Layouter, @@ -683,7 +700,7 @@ fn keccak(msg: &[u8], randomness: F) -> F { let mut keccak = Keccak::default(); keccak.update(msg); RandomLinearCombination::::random_linear_combine( - keccak.digest().try_into().unwrap(), + Word::from_big_endian(keccak.digest().as_slice()).to_le_bytes(), randomness, ) } diff --git a/zkevm-circuits/src/evm_circuit.rs b/zkevm-circuits/src/evm_circuit.rs index 0bf361859b..a47d95a201 100644 --- a/zkevm-circuits/src/evm_circuit.rs +++ b/zkevm-circuits/src/evm_circuit.rs @@ -225,12 +225,17 @@ pub fn load_rws( ) } +// use crate::util::TableShow; + pub fn load_bytecodes( bytecode_table: &[Column; 5], layouter: &mut impl Layouter, bytecodes: &[Bytecode], randomness: F, ) -> Result<(), Error> { + println!("> load_bytecodes"); + // let mut table = TableShow::::new(vec!["codeHash", "tag", "index", + // "isCode", "value"]); layouter.assign_region( || "bytecode table", |mut region| { @@ -247,6 +252,7 @@ pub fn load_bytecodes( for bytecode in bytecodes.iter() { for row in bytecode.table_assignments(randomness) { + let mut column_index = 0; for (column, value) in bytecode_table.iter().zip_eq(row) { region.assign_advice( || format!("bytecode table row {}", offset), @@ -254,10 +260,13 @@ pub fn load_bytecodes( offset, || Ok(value), )?; + // table.push(column_index, value); + column_index += 1; } offset += 1; } } + // table.print(); Ok(()) }, ) diff --git a/zkevm-circuits/src/super_circuit.rs b/zkevm-circuits/src/super_circuit.rs index d17313f587..ce32a428fa 100644 --- a/zkevm-circuits/src/super_circuit.rs +++ b/zkevm-circuits/src/super_circuit.rs @@ -253,7 +253,9 @@ mod super_circuit_tests { }; use ethers_signers::{LocalWallet, Signer}; use group::{Curve, Group}; + use halo2_proofs::arithmetic::Field as Halo2Field; use halo2_proofs::dev::{MockProver, VerifyConfig, VerifyFailure}; + use halo2_proofs::pairing::bn256::Fr; use mock::{TestContext, MOCK_CHAIN_ID}; use rand::SeedableRng; use rand_chacha::ChaCha20Rng; @@ -385,7 +387,8 @@ mod super_circuit_tests { builder .handle_block(&block.eth_block, &block.geth_traces) .expect("could not handle block tx"); - let block = block_convert(&builder.block, &builder.code_db); + let mut block = block_convert(&builder.block, &builder.code_db); + block.randomness = Fr::random(&mut rng); let aux_generator = ::CurveExt::random(&mut rng).to_affine(); diff --git a/zkevm-circuits/src/util.rs b/zkevm-circuits/src/util.rs index 43fdd6564b..4eccc50894 100644 --- a/zkevm-circuits/src/util.rs +++ b/zkevm-circuits/src/util.rs @@ -6,3 +6,68 @@ pub use gadgets::util::Expr; pub(crate) fn random_linear_combine_word(bytes: [u8; 32], randomness: F) -> F { crate::evm_circuit::util::Word::random_linear_combine(bytes, randomness) } + +use itertools::Itertools; + +/// TODO +pub struct TableShow { + names: Vec, + columns: Vec>, +} + +impl TableShow { + /// TODO + pub fn new(names: Vec<&str>) -> Self { + let names_len = names.len(); + Self { + names: names.iter().map(|s| s.to_string()).collect(), + columns: vec![Vec::new(); names_len], + } + } + + /// TODO + pub fn push(&mut self, column_index: usize, v: F) { + self.columns[column_index].push(v); + } + + /// TODO + pub fn print(&self) { + print!("|"); + for name in &self.names { + print!(" {} |", name) + } + println!("\n---"); + let num_bytes: Vec = self + .columns + .iter() + .map(|col| col.iter().max().unwrap()) + .map(|max| { + let max_repr = max.to_repr(); + let bytes = max_repr.as_ref(); + let mut len = 1; + for i in (0..32).rev() { + if bytes[i] != 0 { + len = i + 1; + break; + } + } + len + }) + .collect(); + for row in 0..self.columns[0].len() { + print!("|"); + for col in 0..self.columns.len() { + print!( + " {:02x} |", + self.columns[col][row] + .to_repr() + .as_ref() + .iter() + .take(num_bytes[col]) + .format("") + ); + } + println!(""); + } + } +} From ba5befa5433859bdfc1a790da6f1d543cd26c331 Mon Sep 17 00:00:00 2001 From: Eduard S Date: Tue, 12 Jul 2022 17:40:45 +0200 Subject: [PATCH 09/26] Harmonize tables --- .../src/bytecode_circuit/bytecode_unroller.rs | 21 ++++- zkevm-circuits/src/evm_circuit.rs | 61 ++++++++------ zkevm-circuits/src/evm_circuit/table.rs | 74 ++++++++++++++-- .../evm_circuit/util/constraint_builder.rs | 20 ++--- zkevm-circuits/src/rw_table.rs | 28 +++---- zkevm-circuits/src/super_circuit.rs | 65 +++++++------- zkevm-circuits/src/tx_circuit.rs | 27 +++++- zkevm-circuits/src/tx_circuit/sign_verify.rs | 84 +++++++++---------- 8 files changed, 237 insertions(+), 143 deletions(-) diff --git a/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs b/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs index ed2a3c648d..e2ae4eecba 100644 --- a/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs +++ b/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs @@ -1,6 +1,6 @@ use crate::{ evm_circuit::{ - table::BytecodeFieldTag, + table::{BytecodeFieldTag, TableColumns}, util::{ and, constraint_builder::BaseConstraintBuilder, not, or, select, RandomLinearCombination, @@ -15,6 +15,7 @@ use gadgets::{ is_zero::{IsZeroChip, IsZeroConfig, IsZeroInstruction}, }; use halo2_proofs::{ + arithmetic::FieldExt, circuit::{Layouter, Region}, plonk::{Advice, Column, ConstraintSystem, Error, Expression, Fixed, Selector, VirtualCells}, poly::Rotation, @@ -52,6 +53,24 @@ pub struct BytecodeTable { pub value: Column, } +impl BytecodeTable { + pub fn construct(meta: &mut ConstraintSystem) -> Self { + Self { + hash: meta.advice_column(), + tag: meta.advice_column(), + index: meta.advice_column(), + is_code: meta.advice_column(), + value: meta.advice_column(), + } + } +} + +impl TableColumns for BytecodeTable { + fn columns(&self) -> Vec> { + vec![self.hash, self.tag, self.index, self.is_code, self.value] + } +} + #[derive(Clone, Debug)] pub struct Config { randomness: Expression, diff --git a/zkevm-circuits/src/evm_circuit.rs b/zkevm-circuits/src/evm_circuit.rs index a47d95a201..12187ff5f7 100644 --- a/zkevm-circuits/src/evm_circuit.rs +++ b/zkevm-circuits/src/evm_circuit.rs @@ -11,10 +11,12 @@ pub(crate) mod util; pub mod table; pub mod witness; +use crate::bytecode_circuit::bytecode_unroller::BytecodeTable; +use crate::tx_circuit::TxTable; use eth_types::Field; use execution::ExecutionConfig; use itertools::Itertools; -use table::{FixedTableTag, LookupTable}; +use table::{BlockTable, FixedTableTag, LookupTable, TableColumns}; use witness::Block; /// EvmCircuit implements verification of execution trace of a block. @@ -151,7 +153,7 @@ use crate::{ // replace the specific circuit loader by these? pub fn load_txs( - tx_table: &[Column; 4], + tx_table: &TxTable, layouter: &mut impl Layouter, txs: &[Transaction], randomness: F, @@ -160,10 +162,10 @@ pub fn load_txs( || "tx table", |mut region| { let mut offset = 0; - for column in tx_table { + for column in tx_table.columns() { region.assign_advice( || "tx table all-zero row", - *column, + column, offset, || Ok(F::zero()), )?; @@ -171,10 +173,11 @@ pub fn load_txs( offset += 1; // println!("DBG load_txs"); + let tx_table_columns = tx_table.columns(); for tx in txs.iter() { for row in tx.table_assignments(randomness) { // print!("{:02} ", offset); - for (column, value) in tx_table.iter().zip_eq(row) { + for (column, value) in tx_table_columns.iter().zip_eq(row) { // print!("{:?} ", value); region.assign_advice( || format!("tx table row {}", offset), @@ -228,7 +231,7 @@ pub fn load_rws( // use crate::util::TableShow; pub fn load_bytecodes( - bytecode_table: &[Column; 5], + bytecode_table: &BytecodeTable, layouter: &mut impl Layouter, bytecodes: &[Bytecode], randomness: F, @@ -240,20 +243,21 @@ pub fn load_bytecodes( || "bytecode table", |mut region| { let mut offset = 0; - for column in bytecode_table { + for column in bytecode_table.columns() { region.assign_advice( || "bytecode table all-zero row", - *column, + column, offset, || Ok(F::zero()), )?; } offset += 1; + let bytecode_table_columns = bytecode_table.columns(); for bytecode in bytecodes.iter() { for row in bytecode.table_assignments(randomness) { let mut column_index = 0; - for (column, value) in bytecode_table.iter().zip_eq(row) { + for (column, value) in bytecode_table_columns.iter().zip_eq(row) { region.assign_advice( || format!("bytecode table row {}", offset), *column, @@ -272,7 +276,7 @@ pub fn load_bytecodes( ) } pub fn load_block( - block_table: &[Column; 3], + block_table: &BlockTable, layouter: &mut impl Layouter, block: &BlockContext, randomness: F, @@ -281,18 +285,19 @@ pub fn load_block( || "block table", |mut region| { let mut offset = 0; - for column in block_table { + for column in block_table.columns() { region.assign_advice( || "block table all-zero row", - *column, + column, offset, || Ok(F::zero()), )?; } offset += 1; + let block_table_columns = block_table.columns(); for row in block.table_assignments(randomness) { - for (column, value) in block_table.iter().zip_eq(row) { + for (column, value) in block_table_columns.iter().zip_eq(row) { region.assign_advice( || format!("block table row {}", offset), *column, @@ -351,10 +356,10 @@ pub mod test { #[derive(Clone)] pub struct TestCircuitConfig { - tx_table: [Column; 4], + tx_table: TxTable, rw_table: RwTable, - bytecode_table: [Column; 5], - block_table: [Column; 3], + bytecode_table: BytecodeTable, + block_table: BlockTable, evm_circuit: EvmCircuit, } @@ -535,10 +540,10 @@ pub mod test { } fn configure(meta: &mut ConstraintSystem) -> Self::Config { - let tx_table = [(); 4].map(|_| meta.advice_column()); + let tx_table = TxTable::construct(meta); let rw_table = RwTable::construct(meta); - let bytecode_table = [(); 5].map(|_| meta.advice_column()); - let block_table = [(); 3].map(|_| meta.advice_column()); + let bytecode_table = BytecodeTable::construct(meta); + let block_table = BlockTable::construct(meta); // This gate is used just to get the array of expressions from the power of // randomness instance column, so that later on we don't need to query @@ -558,19 +563,21 @@ pub mod test { power_of_randomness.unwrap() }; + let evm_circuit = EvmCircuit::configure( + meta, + power_of_randomness, + &tx_table, + &rw_table, + &bytecode_table, + &block_table, + ); + Self::Config { tx_table, rw_table, bytecode_table, block_table, - evm_circuit: EvmCircuit::configure( - meta, - power_of_randomness, - &tx_table, - &rw_table, - &bytecode_table, - &block_table, - ), + evm_circuit, } } diff --git a/zkevm-circuits/src/evm_circuit/table.rs b/zkevm-circuits/src/evm_circuit/table.rs index c4325bee50..9162b6f468 100644 --- a/zkevm-circuits/src/evm_circuit/table.rs +++ b/zkevm-circuits/src/evm_circuit/table.rs @@ -1,27 +1,32 @@ use crate::evm_circuit::step::ExecutionState; use crate::impl_expr; pub use crate::tx_circuit::TxFieldTag as TxContextFieldTag; +use eth_types::Field; use halo2_proofs::{ - arithmetic::FieldExt, - plonk::{Advice, Column, Expression, Fixed, VirtualCells}, + plonk::{Advice, Column, ColumnType, ConstraintSystem, Expression, Fixed, VirtualCells}, poly::Rotation, }; use strum::IntoEnumIterator; use strum_macros::{EnumCount, EnumIter}; -pub trait LookupTable { +pub trait TableColumns { + fn columns(&self) -> Vec>; +} + +pub trait LookupTable { fn table_exprs(&self, meta: &mut VirtualCells) -> Vec>; } -impl LookupTable for [Column; W] { +impl> LookupTable for T { fn table_exprs(&self, meta: &mut VirtualCells) -> Vec> { - self.iter() + self.columns() + .iter() .map(|column| meta.query_advice(*column, Rotation::cur())) .collect() } } -impl LookupTable for [Column; W] { +impl LookupTable for [Column; W] { fn table_exprs(&self, meta: &mut VirtualCells) -> Vec> { self.iter() .map(|column| meta.query_fixed(*column, Rotation::cur())) @@ -48,7 +53,7 @@ pub enum FixedTableTag { } impl FixedTableTag { - pub fn build(&self) -> Box> { + pub fn build(&self) -> Box> { let tag = F::from(*self as u64); match self { Self::Zero => Box::new((0..1).map(move |_| [tag, F::zero(), F::zero(), F::zero()])), @@ -330,7 +335,7 @@ pub(crate) enum Lookup { Conditional(Expression, Box>), } -impl Lookup { +impl Lookup { pub(crate) fn conditional(self, condition: Expression) -> Self { Self::Conditional(condition, self.into()) } @@ -407,3 +412,56 @@ impl Lookup { .unwrap() } } + +#[derive(Clone, Debug)] +pub struct BlockTable { + pub tag: Column, + pub index: Column, + pub value: Column, +} + +impl BlockTable { + pub fn construct(meta: &mut ConstraintSystem) -> Self { + Self { + tag: meta.advice_column(), + index: meta.advice_column(), + value: meta.advice_column(), + } + } +} + +impl TableColumns for BlockTable { + fn columns(&self) -> Vec> { + vec![self.tag, self.index, self.value] + } +} + +#[derive(Clone, Debug)] +pub struct KeccakTable { + pub is_enabled: Column, + pub input_rlc: Column, // RLC of input bytes + pub input_len: Column, + pub output_rlc: Column, // RLC of hash of input bytes +} + +impl KeccakTable { + pub fn construct(meta: &mut ConstraintSystem) -> Self { + Self { + is_enabled: meta.advice_column(), + input_rlc: meta.advice_column(), + input_len: meta.advice_column(), + output_rlc: meta.advice_column(), + } + } +} + +impl TableColumns for KeccakTable { + fn columns(&self) -> Vec> { + vec![ + self.is_enabled, + self.input_rlc, + self.input_len, + self.output_rlc, + ] + } +} diff --git a/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs b/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs index a19235c0ca..1d928b3282 100644 --- a/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs +++ b/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs @@ -10,12 +10,10 @@ use crate::{ }, util::Expr, }; -use halo2_proofs::{ - arithmetic::FieldExt, - plonk::{ - Error, - Expression::{self, Constant}, - }, +use eth_types::Field; +use halo2_proofs::plonk::{ + Error, + Expression::{self, Constant}, }; use std::convert::TryInto; @@ -48,7 +46,7 @@ impl Default for Transition { } #[derive(Default)] -pub(crate) struct StepStateTransition { +pub(crate) struct StepStateTransition { pub(crate) rw_counter: Transition>, pub(crate) call_id: Transition>, pub(crate) is_root: Transition>, @@ -62,7 +60,7 @@ pub(crate) struct StepStateTransition { pub(crate) log_id: Transition>, } -impl StepStateTransition { +impl StepStateTransition { pub(crate) fn new_context() -> Self { Self { program_counter: Transition::To(0.expr()), @@ -106,7 +104,7 @@ pub(crate) struct ReversionInfo { reversible_write_counter: Expression, } -impl ReversionInfo { +impl ReversionInfo { pub(crate) fn rw_counter_end_of_reversion(&self) -> Expression { self.rw_counter_end_of_reversion.expr() } @@ -149,7 +147,7 @@ pub struct BaseConstraintBuilder { pub condition: Option>, } -impl BaseConstraintBuilder { +impl BaseConstraintBuilder { pub(crate) fn new(max_degree: usize) -> Self { BaseConstraintBuilder { constraints: Vec::new(), @@ -256,7 +254,7 @@ pub(crate) struct ConstraintBuilder<'a, F> { stored_expressions: Vec>, } -impl<'a, F: FieldExt> ConstraintBuilder<'a, F> { +impl<'a, F: Field> ConstraintBuilder<'a, F> { pub(crate) fn new( curr: Step, next: Step, diff --git a/zkevm-circuits/src/rw_table.rs b/zkevm-circuits/src/rw_table.rs index c08c05dce3..e1f7c261f5 100644 --- a/zkevm-circuits/src/rw_table.rs +++ b/zkevm-circuits/src/rw_table.rs @@ -6,7 +6,7 @@ use halo2_proofs::{ poly::Rotation, }; -use crate::evm_circuit::{table::LookupTable, witness::RwRow}; +use crate::evm_circuit::{table::TableColumns, witness::RwRow}; /// The rw table shared between evm circuit and state circuit #[derive(Clone, Copy)] @@ -24,20 +24,20 @@ pub struct RwTable { pub aux2: Column, } -impl LookupTable for RwTable { - fn table_exprs(&self, meta: &mut VirtualCells) -> Vec> { +impl TableColumns for RwTable { + fn columns(&self) -> Vec> { vec![ - meta.query_advice(self.rw_counter, Rotation::cur()), - meta.query_advice(self.is_write, Rotation::cur()), - meta.query_advice(self.tag, Rotation::cur()), - meta.query_advice(self.key1, Rotation::cur()), - meta.query_advice(self.key2, Rotation::cur()), - meta.query_advice(self.key3, Rotation::cur()), - meta.query_advice(self.key4, Rotation::cur()), - meta.query_advice(self.value, Rotation::cur()), - meta.query_advice(self.value_prev, Rotation::cur()), - meta.query_advice(self.aux1, Rotation::cur()), - meta.query_advice(self.aux2, Rotation::cur()), + self.rw_counter, + self.is_write, + self.tag, + self.key1, + self.key2, + self.key3, + self.key4, + self.value, + self.value_prev, + self.aux1, + self.aux2, ] } } diff --git a/zkevm-circuits/src/super_circuit.rs b/zkevm-circuits/src/super_circuit.rs index ce32a428fa..7187947e82 100644 --- a/zkevm-circuits/src/super_circuit.rs +++ b/zkevm-circuits/src/super_circuit.rs @@ -21,7 +21,7 @@ use crate::bytecode_circuit::bytecode_unroller::{ use crate::util::Expr; use crate::{ evm_circuit::{ - table::FixedTableTag, + table::{BlockTable, FixedTableTag, KeccakTable}, witness::Block, EvmCircuit, {load_block, load_bytecodes, load_rws, load_txs}, }, @@ -38,10 +38,12 @@ use halo2_proofs::{ #[derive(Clone)] pub struct SuperCircuitConfig { - tx_table: [Column; 4], + // tx_table: [Column; 4], + tx_table: TxTable, rw_table: RwTable, - bytecode_table: [Column; 5], - block_table: [Column; 3], + bytecode_table: BytecodeTable, + block_table: BlockTable, + keccak_table: KeccakTable, evm_circuit: EvmCircuit, tx_circuit: TxCircuitConfig, bytecode_circuit: BytecodeConfig, @@ -80,10 +82,11 @@ impl Circuit } fn configure(meta: &mut ConstraintSystem) -> Self::Config { - let tx_table = [(); 4].map(|_| meta.advice_column()); + let tx_table = TxTable::construct(meta); let rw_table = RwTable::construct(meta); - let bytecode_table = [(); 5].map(|_| meta.advice_column()); - let block_table = [(); 3].map(|_| meta.advice_column()); + let bytecode_table = BytecodeTable::construct(meta); + let block_table = BlockTable::construct(meta); + let keccak_table = KeccakTable::construct(meta); // This gate is used just to get the array of expressions from the power of // randomness instance column, so that later on we don't need to query @@ -102,45 +105,37 @@ impl Circuit power_of_randomness.unwrap() }; + let evm_circuit = EvmCircuit::configure( + meta, + power_of_randomness[..31] + .iter() + .cloned() + .collect::>>() + .try_into() + .unwrap(), + &tx_table, + &rw_table, + &bytecode_table, + &block_table, + ); Self::Config { - tx_table, + tx_table: tx_table.clone(), rw_table, - bytecode_table, + bytecode_table: bytecode_table.clone(), block_table, - evm_circuit: EvmCircuit::configure( - meta, - power_of_randomness[..31] - .iter() - .cloned() - .collect::>>() - .try_into() - .unwrap(), - &tx_table, - &rw_table, - &bytecode_table, - &block_table, - ), + keccak_table: keccak_table.clone(), + evm_circuit, tx_circuit: TxCircuitConfig::new( meta, power_of_randomness.clone(), - TxTable { - tx_id: tx_table[0], - tag: tx_table[1], - index: tx_table[2], - value: tx_table[3], - }, + tx_table, + keccak_table, ), bytecode_circuit: BytecodeConfig::configure( meta, power_of_randomness[0].clone(), - BytecodeTable { - hash: bytecode_table[0], - tag: bytecode_table[1], - index: bytecode_table[2], - is_code: bytecode_table[3], - value: bytecode_table[4], - }, + bytecode_table, ), } } diff --git a/zkevm-circuits/src/tx_circuit.rs b/zkevm-circuits/src/tx_circuit.rs index 7b10070b3a..2c3244454b 100644 --- a/zkevm-circuits/src/tx_circuit.rs +++ b/zkevm-circuits/src/tx_circuit.rs @@ -8,6 +8,7 @@ pub mod sign_verify; +use crate::evm_circuit::table::{KeccakTable, TableColumns}; use crate::impl_expr; use crate::util::{random_linear_combine_word as rlc, Expr}; use eth_types::{ @@ -16,9 +17,8 @@ use eth_types::{ use ff::PrimeField; use group::GroupEncoding; use halo2_proofs::{ - // arithmetic::CurveAffine, circuit::{AssignedCell, Layouter, Region, SimpleFloorPlanner}, - plonk::{Advice, Circuit, Column, ConstraintSystem, Error, Expression}, + plonk::{Advice, Circuit, Column, ConstraintSystem, Error, Expression, VirtualCells}, poly::Rotation, }; use itertools::Itertools; @@ -194,11 +194,29 @@ pub struct TxTable { pub value: Column, } +impl TxTable { + pub fn construct(meta: &mut ConstraintSystem) -> Self { + Self { + tx_id: meta.advice_column(), + tag: meta.advice_column(), + index: meta.advice_column(), + value: meta.advice_column(), + } + } +} + +impl TableColumns for TxTable { + fn columns(&self) -> Vec> { + vec![self.tx_id, self.tag, self.index, self.value] + } +} + impl TxCircuitConfig { pub fn new( meta: &mut ConstraintSystem, power_of_randomness: [Expression; sign_verify::POW_RAND_SIZE], tx_table: TxTable, + keccak_table: KeccakTable, ) -> Self { // let tx_id = meta.advice_column(); // let tag = meta.advice_column(); @@ -228,7 +246,7 @@ impl TxCircuitConfig { // power_of_randomness.unwrap() // }; - let sign_verify = SignVerifyConfig::new(meta, power_of_randomness); + let sign_verify = SignVerifyConfig::new(meta, power_of_randomness, keccak_table); Self { tx_id, @@ -473,7 +491,8 @@ impl Circuit power_of_randomness.unwrap() }; - TxCircuitConfig::new(meta, power_of_randomness, tx_table) + let keccak_table = KeccakTable::construct(meta); + TxCircuitConfig::new(meta, power_of_randomness, tx_table, keccak_table) } fn synthesize( diff --git a/zkevm-circuits/src/tx_circuit/sign_verify.rs b/zkevm-circuits/src/tx_circuit/sign_verify.rs index 736a7653e4..4756432c11 100644 --- a/zkevm-circuits/src/tx_circuit/sign_verify.rs +++ b/zkevm-circuits/src/tx_circuit/sign_verify.rs @@ -5,15 +5,19 @@ // - *_le: Little-Endian bytes use crate::{ - evm_circuit::util::{not, RandomLinearCombination, Word}, + evm_circuit::{ + table::KeccakTable, + util::{not, RandomLinearCombination, Word}, + }, util::Expr, }; use ecc::{EccConfig, GeneralEccChip}; use ecdsa::ecdsa::{AssignedEcdsaSig, AssignedPublicKey, EcdsaChip}; +use eth_types::Field; use gadgets::is_zero::{IsZeroChip, IsZeroConfig, IsZeroInstruction}; -use group::{ff::Field, prime::PrimeCurveAffine, Curve}; +use group::{ff::Field as GroupField, prime::PrimeCurveAffine, Curve}; use halo2_proofs::{ - arithmetic::{BaseExt, Coordinates, CurveAffine, FieldExt}, + arithmetic::{BaseExt, Coordinates, CurveAffine}, circuit::{AssignedCell, Layouter, Region}, plonk::{Advice, Column, ConstraintSystem, Error, Expression, Selector}, poly::Rotation, @@ -47,7 +51,7 @@ pub const VERIF_HEIGHT: usize = 1; /// Auxiliary Gadget to verify a that a message hash is signed by the public /// key corresponding to an Ethereum Address. #[derive(Clone, Default, Debug)] -pub struct SignVerifyChip { +pub struct SignVerifyChip { /// Aux generator for EccChip pub aux_generator: Secp256k1Affine, /// Window size for EccChip @@ -56,11 +60,6 @@ pub struct SignVerifyChip { pub _marker: PhantomData, } -const KECCAK_IS_ENABLED: usize = 0; -const KECCAK_INPUT_RLC: usize = 1; -const KECCAK_INPUT_LEN: usize = 2; -const KECCAK_OUTPUT_RLC: usize = 3; - const NUMBER_OF_LIMBS: usize = 4; const BIT_LEN_LIMB: usize = 72; @@ -77,7 +76,7 @@ pub(crate) fn pk_bytes_swap_endianness(pk: &[T]) -> [T; 64] { /// Return an expression that builds an integer element in the field from the /// `bytes` in big endian. -fn int_from_bytes_be(bytes: &[Expression]) -> Expression { +fn int_from_bytes_be(bytes: &[Expression]) -> Expression { // sum_{i = 0}^{N} bytes[i] * 256^i let mut res = 0u8.expr(); for (i, byte) in bytes.iter().rev().enumerate() { @@ -88,7 +87,7 @@ fn int_from_bytes_be(bytes: &[Expression]) -> Expression { /// Constraint equality (using copy constraints) between `src` integer bytes and /// `dst` integer bytes. Then assign the `dst` values from `src`. -fn copy_integer_bytes_le( +fn copy_integer_bytes_le( region: &mut Region<'_, F>, name: &str, src: &[AssignedValue; 32], @@ -109,7 +108,7 @@ fn copy_integer_bytes_le( /// SignVerify Configuration #[derive(Debug, Clone)] -pub(crate) struct SignVerifyConfig { +pub(crate) struct SignVerifyConfig { q_enable: Selector, pk_hash: [Column; 32], // When address is 0, we disable the signature verification by using a dummy pk, msg_hash and @@ -129,13 +128,14 @@ pub(crate) struct SignVerifyConfig { power_of_randomness: [Expression; POW_RAND_SIZE], // [is_enabled, input_rlc, input_len, output_rlc] - keccak_table: [Column; 4], + keccak_table: KeccakTable, } -impl SignVerifyConfig { +impl SignVerifyConfig { pub(crate) fn new( meta: &mut ConstraintSystem, power_of_randomness: [Expression; POW_RAND_SIZE], + keccak_table: KeccakTable, ) -> Self { let q_enable = meta.complex_selector(); @@ -164,9 +164,6 @@ impl SignVerifyConfig { // is_not_padding == address != 0 let is_not_padding = not::expr(address_is_zero.is_zero_expression.clone()); - // lookup keccak table - let keccak_table = [(); 4].map(|_| meta.advice_column()); - // 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 // in the ecdsa_chip @@ -177,13 +174,11 @@ impl SignVerifyConfig { let mut table_map = Vec::new(); // Column 0: is_enabled - let keccak_is_enabled = - meta.query_advice(keccak_table[KECCAK_IS_ENABLED], Rotation::cur()); + let keccak_is_enabled = meta.query_advice(keccak_table.is_enabled, Rotation::cur()); table_map.push((selector.clone(), keccak_is_enabled)); // Column 1: input_rlc (pk_rlc) - let keccak_input_rlc = - meta.query_advice(keccak_table[KECCAK_INPUT_RLC], Rotation::cur()); + let keccak_input_rlc = meta.query_advice(keccak_table.input_rlc, Rotation::cur()); let pk_le: [Expression; 64] = pk .map(|coord| coord.map(|c| meta.query_advice(c, Rotation::cur()))) .iter() @@ -198,13 +193,11 @@ impl SignVerifyConfig { table_map.push((selector.clone() * pk_rlc, keccak_input_rlc)); // Column 2: input_len (64) - let keccak_input_len = - meta.query_advice(keccak_table[KECCAK_INPUT_LEN], Rotation::cur()); + let keccak_input_len = meta.query_advice(keccak_table.input_len, Rotation::cur()); table_map.push((selector.clone() * 64usize.expr(), keccak_input_len)); // Column 3: output_rlc (pk_hash_rlc) - let keccak_output_rlc = - meta.query_advice(keccak_table[KECCAK_OUTPUT_RLC], Rotation::cur()); + let keccak_output_rlc = meta.query_advice(keccak_table.output_rlc, Rotation::cur()); let pk_hash = pk_hash.map(|c| meta.query_advice(c, Rotation::cur())); let pk_hash_rlc = RandomLinearCombination::random_linear_combine_expr(pk_hash, &power_of_randomness); @@ -270,7 +263,7 @@ pub(crate) struct KeccakAux { output: [u8; 32], } -impl SignVerifyConfig { +impl SignVerifyConfig { pub(crate) fn load_range(&self, layouter: &mut impl Layouter) -> Result<(), Error> { let bit_len_lookup = BIT_LEN_LIMB / NUMBER_OF_LOOKUP_LIMBS; let range_chip = RangeChip::::new(self.range_config.clone(), bit_len_lookup); @@ -290,10 +283,14 @@ impl SignVerifyConfig { output_rlc: F, ) -> Result<(), Error> { for (name, column, value) in &[ - ("is_enabled", self.keccak_table[0], is_enabled), - ("input_rlc", self.keccak_table[1], input_rlc), - ("input_len", self.keccak_table[2], F::from(input_len as u64)), - ("output_rlc", self.keccak_table[3], output_rlc), + ("is_enabled", self.keccak_table.is_enabled, is_enabled), + ("input_rlc", self.keccak_table.input_rlc, input_rlc), + ( + "input_len", + self.keccak_table.input_len, + F::from(input_len as u64), + ), + ("output_rlc", self.keccak_table.output_rlc, output_rlc), ] { region.assign_advice( || format!("Keccak table assign {} {}", name, offset), @@ -350,20 +347,20 @@ impl SignVerifyConfig { } } -pub(crate) struct AssignedECDSA { +pub(crate) struct AssignedECDSA { pk_x_le: [AssignedValue; 32], pk_y_le: [AssignedValue; 32], msg_hash_le: [AssignedValue; 32], } #[derive(Debug)] -pub(crate) struct AssignedSignatureVerify { +pub(crate) struct AssignedSignatureVerify { pub(crate) address: AssignedCell, pub(crate) msg_hash_rlc: AssignedCell, } // Returns assigned constants [256^1, 256^2, .., 256^{n-1}] -fn assign_pows_256( +fn assign_pows_256( ctx: &mut RegionCtx<'_, '_, F>, main_gate: &MainGate, n: usize, @@ -378,7 +375,7 @@ fn assign_pows_256( // Return an array of bytes that corresponds to the little endian representation // of the integer, adding the constraints to verify the correctness of the // conversion (byte range check included). -fn integer_to_bytes_le( +fn integer_to_bytes_le( ctx: &mut RegionCtx<'_, '_, F>, main_gate: &MainGate, range_chip: &RangeChip, @@ -412,7 +409,7 @@ fn integer_to_bytes_le( /// Helper structure pass around references to all the chips required for an /// ECDSA veficication. -struct ChipsRef<'a, F: FieldExt, const NUMBER_OF_LIMBS: usize, const BIT_LEN_LIMB: usize> { +struct ChipsRef<'a, F: Field, const NUMBER_OF_LIMBS: usize, const BIT_LEN_LIMB: usize> { main_gate: &'a MainGate, range_chip: &'a RangeChip, ecc_chip: &'a GeneralEccChip, @@ -420,7 +417,7 @@ struct ChipsRef<'a, F: FieldExt, const NUMBER_OF_LIMBS: usize, const BIT_LEN_LIM ecdsa_chip: &'a EcdsaChip, } -impl SignVerifyChip { +impl SignVerifyChip { fn assign_aux( &self, region: &mut Region<'_, F>, @@ -792,7 +789,7 @@ impl Default for SignData { } } -fn pub_key_hash_to_address(pk_hash: &[u8]) -> F { +fn pub_key_hash_to_address(pk_hash: &[u8]) -> F { pk_hash[32 - 20..] .iter() .fold(F::zero(), |acc, b| acc * F::from(256) + F::from(*b as u64)) @@ -810,11 +807,11 @@ mod sign_verify_tests { use rand_xorshift::XorShiftRng; #[derive(Clone, Debug)] - struct TestCircuitSignVerifyConfig { + struct TestCircuitSignVerifyConfig { sign_verify: SignVerifyConfig, } - impl TestCircuitSignVerifyConfig { + impl TestCircuitSignVerifyConfig { pub(crate) fn new(meta: &mut ConstraintSystem) -> Self { // This gate is used just to get the array of expressions from the power of // randomness instance column, so that later on we don't need to query @@ -833,20 +830,21 @@ mod sign_verify_tests { power_of_randomness.unwrap() }; + let keccak_table = KeccakTable::construct(meta); - let sign_verify = SignVerifyConfig::new(meta, power_of_randomness); + let sign_verify = SignVerifyConfig::new(meta, power_of_randomness, keccak_table); TestCircuitSignVerifyConfig { sign_verify } } } #[derive(Default)] - struct TestCircuitSignVerify { + struct TestCircuitSignVerify { sign_verify: SignVerifyChip, randomness: F, signatures: Vec, } - impl Circuit for TestCircuitSignVerify { + impl Circuit for TestCircuitSignVerify { type Config = TestCircuitSignVerifyConfig; type FloorPlanner = SimpleFloorPlanner; @@ -873,7 +871,7 @@ mod sign_verify_tests { } } - fn run(k: u32, signatures: Vec) { + fn run(k: u32, signatures: Vec) { let mut rng = XorShiftRng::seed_from_u64(2); let aux_generator = ::CurveExt::random(&mut rng).to_affine(); From 1dfa99cd607e3837af4b3351840386252ee90f00 Mon Sep 17 00:00:00 2001 From: Eduard S Date: Tue, 12 Jul 2022 17:48:45 +0200 Subject: [PATCH 10/26] Reuse keccak table between TxCircuit and BytecodeCircuit --- .../src/bytecode_circuit/bytecode_unroller.rs | 25 ++++++++++++------- zkevm-circuits/src/super_circuit.rs | 3 ++- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs b/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs index e2ae4eecba..f570357ec9 100644 --- a/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs +++ b/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs @@ -1,6 +1,6 @@ use crate::{ evm_circuit::{ - table::{BytecodeFieldTag, TableColumns}, + table::{BytecodeFieldTag, KeccakTable, TableColumns}, util::{ and, constraint_builder::BaseConstraintBuilder, not, or, select, RandomLinearCombination, @@ -94,7 +94,8 @@ pub struct Config { length_inv: Column, length_is_zero: IsZeroConfig, push_table: [Column; PUSH_TABLE_WIDTH], - keccak_table: [Column; KECCAK_WIDTH], + // keccak_table: [Column; KECCAK_WIDTH], + keccak_table: KeccakTable, } impl Config { @@ -102,6 +103,7 @@ impl Config { meta: &mut ConstraintSystem, randomness: Expression, bytecode_table: BytecodeTable, + keccak_table: KeccakTable, ) -> Self { let q_enable = meta.fixed_column(); let q_first = meta.fixed_column(); @@ -120,7 +122,6 @@ impl Config { let push_rindex_inv = meta.advice_column(); let length_inv = meta.advice_column(); let push_table = array_init::array_init(|_| meta.fixed_column()); - let keccak_table = array_init::array_init(|_| meta.advice_column()); // A byte is an opcode when `push_rindex == 0` on the previous row, // else it's push data. @@ -393,10 +394,14 @@ impl Config { ]); let lookup_columns = vec![hash_rlc, hash_length, hash]; let mut constraints = vec![]; - for i in 0..KECCAK_WIDTH { + constraints.push(( + enable.clone(), + meta.query_advice(keccak_table.is_enabled, Rotation::cur()), + )); + for (i, column) in keccak_table.columns().iter().skip(1).enumerate() { constraints.push(( enable.clone() * meta.query_advice(lookup_columns[i], Rotation::cur()), - meta.query_advice(keccak_table[i], Rotation::cur()), + meta.query_advice(*column, Rotation::cur()), )) } constraints @@ -653,9 +658,10 @@ impl Config { let rlc: F = linear_combine(bytecode.clone(), randomness); let size = F::from(bytecode.len() as u64); for (name, column, value) in &[ - ("rlc", self.keccak_table[0], rlc), - ("size", self.keccak_table[1], size), - ("hash", self.keccak_table[2], hash), + ("is_enable", self.keccak_table.is_enabled, F::one()), + ("input_rlc", self.keccak_table.input_rlc, rlc), + ("input_len", self.keccak_table.input_len, size), + ("output_rlc", self.keccak_table.output_rlc, hash), ] { region.assign_advice( || format!("Keccak table assign {} {}", name, offset), @@ -800,8 +806,9 @@ mod tests { randomness.unwrap() }; + let keccak_table = KeccakTable::construct(meta); - Config::configure(meta, randomness, bytecode_table) + Config::configure(meta, randomness, bytecode_table, keccak_table) } fn synthesize( diff --git a/zkevm-circuits/src/super_circuit.rs b/zkevm-circuits/src/super_circuit.rs index 7187947e82..0f1ec0270b 100644 --- a/zkevm-circuits/src/super_circuit.rs +++ b/zkevm-circuits/src/super_circuit.rs @@ -130,12 +130,13 @@ impl Circuit meta, power_of_randomness.clone(), tx_table, - keccak_table, + keccak_table.clone(), ), bytecode_circuit: BytecodeConfig::configure( meta, power_of_randomness[0].clone(), bytecode_table, + keccak_table, ), } } From 21b81f5bf335e6791bca3de69cace6a1899563bc Mon Sep 17 00:00:00 2001 From: Eduard S Date: Thu, 14 Jul 2022 17:45:45 +0200 Subject: [PATCH 11/26] WIP --- .../src/bytecode_circuit/bytecode_unroller.rs | 253 ++++++++++-------- zkevm-circuits/src/evm_circuit.rs | 92 +++++-- zkevm-circuits/src/evm_circuit/table.rs | 2 + zkevm-circuits/src/super_circuit.rs | 38 ++- zkevm-circuits/src/tx_circuit.rs | 33 ++- zkevm-circuits/src/tx_circuit/sign_verify.rs | 89 ++++-- 6 files changed, 343 insertions(+), 164 deletions(-) diff --git a/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs b/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs index f570357ec9..6852eff6d2 100644 --- a/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs +++ b/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs @@ -2,7 +2,7 @@ use crate::{ evm_circuit::{ table::{BytecodeFieldTag, KeccakTable, TableColumns}, util::{ - and, constraint_builder::BaseConstraintBuilder, not, or, select, + and, constraint_builder::BaseConstraintBuilder, not, or, rlc, select, RandomLinearCombination, }, }, @@ -30,7 +30,7 @@ use super::param::{KECCAK_WIDTH, PUSH_TABLE_WIDTH}; /// Public data for the bytecode #[derive(Clone, Debug, PartialEq)] pub(crate) struct BytecodeRow { - hash: F, + code_hash: F, tag: F, index: F, is_code: F, @@ -44,9 +44,11 @@ pub struct UnrolledBytecode { rows: Vec>, } +// CHANGELOG: Added BytecodeTable to help reusing the table config with other +// circuits #[derive(Clone, Debug)] pub struct BytecodeTable { - pub hash: Column, + pub code_hash: Column, // CHANGELOG: Renamed from hash pub tag: Column, pub index: Column, pub is_code: Column, @@ -56,7 +58,7 @@ pub struct BytecodeTable { impl BytecodeTable { pub fn construct(meta: &mut ConstraintSystem) -> Self { Self { - hash: meta.advice_column(), + code_hash: meta.advice_column(), tag: meta.advice_column(), index: meta.advice_column(), is_code: meta.advice_column(), @@ -67,7 +69,13 @@ impl BytecodeTable { impl TableColumns for BytecodeTable { fn columns(&self) -> Vec> { - vec![self.hash, self.tag, self.index, self.is_code, self.value] + vec![ + self.code_hash, + self.tag, + self.index, + self.is_code, + self.value, + ] } } @@ -78,14 +86,10 @@ pub struct Config { q_enable: Column, q_first: Column, q_last: Selector, - hash: Column, // * - tag: Column, // * - index: Column, // * - is_code: Column, // * - value: Column, // * + bytecode_table: BytecodeTable, push_rindex: Column, - hash_rlc: Column, - hash_length: Column, + hash_input_rlc: Column, + code_length: Column, // CHANGELOG: Renamed from hash_length byte_push_size: Column, is_final: Column, padding: Column, @@ -94,10 +98,11 @@ pub struct Config { length_inv: Column, length_is_zero: IsZeroConfig, push_table: [Column; PUSH_TABLE_WIDTH], - // keccak_table: [Column; KECCAK_WIDTH], keccak_table: KeccakTable, } +use crate::util::TableShow; + impl Config { pub(crate) fn configure( meta: &mut ConstraintSystem, @@ -108,14 +113,14 @@ impl Config { let q_enable = meta.fixed_column(); let q_first = meta.fixed_column(); let q_last = meta.selector(); - let hash = bytecode_table.hash; - let tag = bytecode_table.tag; - let index = bytecode_table.index; - let is_code = bytecode_table.is_code; + // let code_hash = bytecode_table.code_hash; + // let tag = bytecode_table.tag; + // let index = bytecode_table.index; + // let is_code = bytecode_table.is_code; let value = bytecode_table.value; let push_rindex = meta.advice_column(); - let hash_rlc = meta.advice_column(); - let hash_length = meta.advice_column(); + let hash_input_rlc = meta.advice_column(); + let code_length = meta.advice_column(); let byte_push_size = meta.advice_column(); let is_final = meta.advice_column(); let padding = meta.advice_column(); @@ -141,7 +146,7 @@ impl Config { let is_row_tag_length = |meta: &mut VirtualCells| { and::expr(vec![ not::expr(meta.query_advice(padding, Rotation::cur())), - not::expr(meta.query_advice(tag, Rotation::cur())), + not::expr(meta.query_advice(bytecode_table.tag, Rotation::cur())), ]) }; @@ -149,7 +154,7 @@ impl Config { let is_row_tag_byte = |meta: &mut VirtualCells| { and::expr(vec![ not::expr(meta.query_advice(padding, Rotation::cur())), - meta.query_advice(tag, Rotation::cur()), + meta.query_advice(bytecode_table.tag, Rotation::cur()), ]) }; @@ -179,22 +184,22 @@ impl Config { and::expr(vec![ not::expr(meta.query_fixed(q_first, Rotation::cur())), not::expr(meta.query_advice(padding, Rotation::prev())), - not::expr(meta.query_advice(tag, Rotation::prev())), + not::expr(meta.query_advice(bytecode_table.tag, Rotation::prev())), ]) }; cb.require_equal( "if prev_row.tag == Length: index == 0 else index == index + 1", - meta.query_advice(index, Rotation::cur()), + meta.query_advice(bytecode_table.index, Rotation::cur()), select::expr( is_prev_row_tag_length(meta), 0.expr(), - meta.query_advice(index, Rotation::prev()) + 1.expr(), + meta.query_advice(bytecode_table.index, Rotation::prev()) + 1.expr(), ), ); cb.require_equal( "is_code := push_rindex_prev == 0", - meta.query_advice(is_code, Rotation::cur()), + meta.query_advice(bytecode_table.is_code, Rotation::cur()), select::expr( is_prev_row_tag_length(meta), 1.expr(), @@ -202,20 +207,20 @@ impl Config { ), ); cb.require_equal( - "hash_rlc := hash_rlc_prev * randomness + byte", - meta.query_advice(hash_rlc, Rotation::cur()), - meta.query_advice(hash_rlc, Rotation::prev()) * randomness.clone() + "hash_input_rlc := hash_input_rlc_prev * randomness + byte", + meta.query_advice(hash_input_rlc, Rotation::cur()), + meta.query_advice(hash_input_rlc, Rotation::prev()) * randomness.clone() + meta.query_advice(value, Rotation::cur()), ); cb.require_equal( - "hash needs to remain the same", - meta.query_advice(hash, Rotation::cur()), - meta.query_advice(hash, Rotation::prev()), + "code_hash needs to remain the same", + meta.query_advice(bytecode_table.code_hash, Rotation::cur()), + meta.query_advice(bytecode_table.code_hash, Rotation::prev()), ); cb.require_equal( - "hash_length needs to remain the same", - meta.query_advice(hash_length, Rotation::cur()), - meta.query_advice(hash_length, Rotation::prev()), + "code_length needs to remain the same", + meta.query_advice(code_length, Rotation::cur()), + meta.query_advice(code_length, Rotation::prev()), ); cb.require_equal( "padding needs to remain the same", @@ -235,7 +240,7 @@ impl Config { let mut cb = BaseConstraintBuilder::default(); cb.require_equal( "next_row.tag == (tag.Length or tag.Padding) if length == 0 else tag.Byte", - meta.query_advice(tag, Rotation::next()), + meta.query_advice(bytecode_table.tag, Rotation::next()), select::expr( length_is_zero.clone().is_zero_expression, select::expr( @@ -247,16 +252,16 @@ impl Config { ), ); cb.require_equal( - "if row.tag == tag.Length: value == row.hash_length", + "if row.tag == tag.Length: value == row.code_length", meta.query_advice(value, Rotation::cur()), - meta.query_advice(hash_length, Rotation::cur()), + meta.query_advice(code_length, Rotation::cur()), ); // FIXME: Since randomness is only known at synthesis time, the RLC of empty - // hash is not constant. Consider doing a lookup to the empty hash + // code_hash is not constant. Consider doing a lookup to the empty code_hash // value? cb.condition(length_is_zero.clone().is_zero_expression, // |cb| { cb.require_equal( - // "if length == 0: hash == RLC(EMPTY_HASH, randomness)", - // meta.query_advice(hash, Rotation::cur()), + // "if length == 0: code_hash == RLC(EMPTY_HASH, randomness)", + // meta.query_advice(bytecode_table.code_hash, Rotation::cur()), // Expression::Constant(keccak(&[], randomness)), // ); // }); @@ -292,9 +297,9 @@ impl Config { let mut cb = BaseConstraintBuilder::default(); cb.condition(1.expr() - length_is_zero.clone().is_zero_expression, |cb| { cb.require_equal( - "index + 1 needs to equal hash_length", - meta.query_advice(index, Rotation::cur()) + 1.expr(), - meta.query_advice(hash_length, Rotation::cur()), + "index + 1 needs to equal code_length", + meta.query_advice(bytecode_table.index, Rotation::cur()) + 1.expr(), + meta.query_advice(code_length, Rotation::cur()), ); }); // Conditions: @@ -323,7 +328,7 @@ impl Config { "push_rindex := is_code ? byte_push_size : push_rindex_prev - 1", meta.query_advice(push_rindex, Rotation::cur()), select::expr( - meta.query_advice(is_code, Rotation::cur()), + meta.query_advice(bytecode_table.is_code, Rotation::cur()), meta.query_advice(byte_push_size, Rotation::cur()), meta.query_advice(push_rindex, Rotation::prev()) - 1.expr(), ), @@ -348,7 +353,7 @@ impl Config { ])) }); - // The hash is checked on the latest row because only then have + // The code_hash is checked on the latest row because only then have // we accumulated all the bytes. We also have to go through the bytes // in a forward manner because that's the only way we can know which // bytes are op codes and which are push data. @@ -392,8 +397,9 @@ impl Config { meta.query_advice(is_final, Rotation::cur()), not::expr(meta.query_advice(padding, Rotation::cur())), ]); - let lookup_columns = vec![hash_rlc, hash_length, hash]; + let lookup_columns = vec![hash_input_rlc, code_length, bytecode_table.code_hash]; let mut constraints = vec![]; + // CHANGELOG: Add is_enabled expression to the keccak lookup constraints.push(( enable.clone(), meta.query_advice(keccak_table.is_enabled, Rotation::cur()), @@ -413,14 +419,10 @@ impl Config { q_enable, q_first, q_last, - hash, - tag, - index, - is_code, - value, + bytecode_table, push_rindex, - hash_rlc, - hash_length, + hash_input_rlc, + code_length, byte_push_size, is_final, padding, @@ -459,8 +461,8 @@ impl Config { // Run over all the bytes let mut push_rindex = 0; let mut byte_push_size = 0; - let mut hash_rlc = F::zero(); - let hash_length = F::from(bytecode.bytes.len() as u64); + let mut hash_input_rlc = F::zero(); + let code_length = F::from(bytecode.bytes.len() as u64); for (idx, row) in bytecode.rows.iter().enumerate() { // Track which byte is an opcode and which is push // data @@ -472,7 +474,7 @@ impl Config { } else { push_rindex - 1 }; - hash_rlc = hash_rlc * randomness + row.value; + hash_input_rlc = hash_input_rlc * randomness + row.value; } // Set the data for this row @@ -484,14 +486,14 @@ impl Config { offset, true, offset == last_row_offset, - row.hash, + row.code_hash, row.tag, row.index, row.is_code, row.value, push_rindex, - hash_rlc, - hash_length, + hash_input_rlc, + code_length, F::from(byte_push_size as u64), idx == bytecode.bytes.len(), false, @@ -499,7 +501,7 @@ impl Config { )?; push_rindex_prev = push_rindex; offset += 1; - // table.push(0, row.hash); + // table.push(0, row.code_hash); // table.push(1, row.tag); // table.push(2, row.index); // table.push(3, row.is_code); @@ -552,14 +554,14 @@ impl Config { offset: usize, enable: bool, last: bool, - hash: F, + code_hash: F, tag: F, index: F, is_code: F, value: F, push_rindex: u64, - hash_rlc: F, - hash_length: F, + hash_input_rlc: F, + code_length: F, byte_push_size: F, is_final: bool, padding: bool, @@ -588,14 +590,14 @@ impl Config { // Advices for (name, column, value) in &[ - ("hash", self.hash, hash), - ("tag", self.tag, tag), - ("index", self.index, index), - ("is_code", self.is_code, is_code), - ("value", self.value, value), + ("code_hash", self.bytecode_table.code_hash, code_hash), + ("tag", self.bytecode_table.tag, tag), + ("index", self.bytecode_table.index, index), + ("is_code", self.bytecode_table.is_code, is_code), + ("value", self.bytecode_table.value, value), ("push_rindex", self.push_rindex, F::from(push_rindex)), - ("hash_rlc", self.hash_rlc, hash_rlc), - ("hash_length", self.hash_length, hash_length), + ("hash_input_rlc", self.hash_input_rlc, hash_input_rlc), + ("code_length", self.code_length, code_length), ("byte_push_size", self.byte_push_size, byte_push_size), ("is_final", self.is_final, F::from(is_final as u64)), ("padding", self.padding, F::from(padding as u64)), @@ -612,11 +614,55 @@ impl Config { push_rindex_is_zero_chip.assign(region, offset, Some(push_rindex_prev))?; // length_is_zero chip - length_is_zero_chip.assign(region, offset, Some(hash_length))?; + length_is_zero_chip.assign(region, offset, Some(code_length))?; Ok(()) } + // CHANGELOG: Moved to a new function to allow not calling it when integrating + // circuits together. + pub(crate) fn load_keccaks( + &self, + layouter: &mut impl Layouter, + bytecodes: &[UnrolledBytecode], + randomness: F, + ) -> Result<(), Error> { + println!("> bytecode_circuit.load_keccaks"); + let mut table = + TableShow::::new(vec!["is_enabled", "input_rlc", "input_len", "output_rlc"]); + layouter.assign_region( + || "keccak table", + |mut region| { + for (offset, bytecode) in bytecodes.iter().map(|v| v.bytes.clone()).enumerate() { + let code_hash: F = keccak(&bytecode[..], randomness); + println!("+ {:?}", bytecode); + // CHANGELOG: Fixed rlc of input in the correct order. + let input_rlc: F = rlc::value(&bytecode, randomness); + let size = F::from(bytecode.len() as u64); + for (name, column, value) in &[ + ("is_enable", self.keccak_table.is_enabled, F::one()), + ("input_rlc", self.keccak_table.input_rlc, input_rlc), + ("input_len", self.keccak_table.input_len, size), + ("output_rlc", self.keccak_table.output_rlc, code_hash), + ] { + region.assign_advice( + || format!("Keccak table assign {} {}", name, offset), + *column, + offset, + || Ok(*value), + )?; + } + table.push(0, F::one()); + table.push(1, input_rlc); + table.push(2, size); + table.push(3, code_hash); + } + table.print(); + Ok(()) + }, + ) + } + /// load tables pub(crate) fn load( &self, @@ -648,40 +694,17 @@ impl Config { Ok(()) }, )?; + // TODO: Remove this + self.load_keccaks(layouter, bytecodes, randomness)?; - // keccak table - layouter.assign_region( - || "keccak table", - |mut region| { - for (offset, bytecode) in bytecodes.iter().map(|v| v.bytes.clone()).enumerate() { - let hash: F = keccak(&bytecode[..], randomness); - let rlc: F = linear_combine(bytecode.clone(), randomness); - let size = F::from(bytecode.len() as u64); - for (name, column, value) in &[ - ("is_enable", self.keccak_table.is_enabled, F::one()), - ("input_rlc", self.keccak_table.input_rlc, rlc), - ("input_len", self.keccak_table.input_len, size), - ("output_rlc", self.keccak_table.output_rlc, hash), - ] { - region.assign_advice( - || format!("Keccak table assign {} {}", name, offset), - *column, - offset, - || Ok(*value), - )?; - } - } - Ok(()) - }, - )?; Ok(()) } } pub fn unroll(bytes: Vec, randomness: F) -> UnrolledBytecode { - let hash = keccak(&bytes[..], randomness); + let code_hash = keccak(&bytes[..], randomness); let mut rows = vec![BytecodeRow:: { - hash, + code_hash, tag: F::from(BytecodeFieldTag::Length as u64), index: F::zero(), is_code: F::zero(), @@ -699,7 +722,7 @@ pub fn unroll(bytes: Vec, randomness: F) -> UnrolledBytecode { }; rows.push(BytecodeRow:: { - hash, + code_hash, tag: F::from(BytecodeFieldTag::Byte as u64), index: F::from(index as u64), is_code: F::from(is_code as u64), @@ -724,6 +747,7 @@ fn get_push_size(byte: u8) -> u64 { fn keccak(msg: &[u8], randomness: F) -> F { let mut keccak = Keccak::default(); keccak.update(msg); + // CHANGELOG: Fixed endianness RandomLinearCombination::::random_linear_combine( Word::from_big_endian(keccak.digest().as_slice()).to_le_bytes(), randomness, @@ -784,7 +808,7 @@ mod tests { fn configure(meta: &mut ConstraintSystem) -> Self::Config { let bytecode_table = BytecodeTable { - hash: meta.advice_column(), + code_hash: meta.advice_column(), tag: meta.advice_column(), index: meta.advice_column(), is_code: meta.advice_column(), @@ -817,6 +841,7 @@ mod tests { mut layouter: impl Layouter, ) -> Result<(), Error> { config.load(&mut layouter, &self.bytecodes, self.randomness)?; + config.load_keccaks(&mut layouter, &self.bytecodes, self.randomness)?; config.assign(&mut layouter, self.size, &self.bytecodes, self.randomness)?; Ok(()) } @@ -855,7 +880,7 @@ mod tests { if !is_push(byte) { bytecode.write(byte); rows.push(BytecodeRow { - hash: Fr::zero(), + code_hash: Fr::zero(), tag: Fr::from(BytecodeFieldTag::Byte as u64), index: Fr::from(rows.len() as u64), is_code: Fr::from(true as u64), @@ -868,7 +893,7 @@ mod tests { let data_byte = OpcodeId::PUSH32.as_u8(); bytecode.push(n, Word::from_little_endian(&vec![data_byte; n][..])); rows.push(BytecodeRow { - hash: Fr::zero(), + code_hash: Fr::zero(), tag: Fr::from(BytecodeFieldTag::Byte as u64), index: Fr::from(rows.len() as u64), is_code: Fr::from(true as u64), @@ -876,7 +901,7 @@ mod tests { }); for _ in 0..n { rows.push(BytecodeRow { - hash: Fr::zero(), + code_hash: Fr::zero(), tag: Fr::from(BytecodeFieldTag::Byte as u64), index: Fr::from(rows.len() as u64), is_code: Fr::from(false as u64), @@ -884,15 +909,15 @@ mod tests { }); } } - // Set the hash of the complete bytecode in the rows - let hash = keccak(&bytecode.to_vec()[..], randomness); + // Set the code_hash of the complete bytecode in the rows + let code_hash = keccak(&bytecode.to_vec()[..], randomness); for row in rows.iter_mut() { - row.hash = hash; + row.code_hash = code_hash; } rows.insert( 0, BytecodeRow { - hash, + code_hash, tag: Fr::from(BytecodeFieldTag::Length as u64), index: Fr::zero(), is_code: Fr::zero(), @@ -991,7 +1016,7 @@ mod tests { ); } - /// Test invalid hash data + /// Test invalid code_hash data #[test] fn bytecode_invalid_hash_data() { let k = 9; @@ -999,23 +1024,23 @@ mod tests { let bytecode = vec![8u8, 2, 3, 8, 9, 7, 128]; let unrolled = unroll(bytecode, randomness); verify::(k, vec![unrolled.clone()], randomness, true); - // Change the hash on the first position + // Change the code_hash on the first position { let mut invalid = unrolled.clone(); - invalid.rows[0].hash += Fr::from(1u64); + invalid.rows[0].code_hash += Fr::from(1u64); verify::(k, vec![invalid], randomness, false); } - // Change the hash on another position + // Change the code_hash on another position { let mut invalid = unrolled.clone(); - invalid.rows[4].hash += Fr::from(1u64); + invalid.rows[4].code_hash += Fr::from(1u64); verify::(k, vec![invalid], randomness, false); } - // Change all the hashes so it doesn't match the keccak lookup hash + // Change all the hashes so it doesn't match the keccak lookup code_hash { let mut invalid = unrolled; for row in invalid.rows.iter_mut() { - row.hash = Fr::one(); + row.code_hash = Fr::one(); } verify::(k, vec![invalid], randomness, false); } diff --git a/zkevm-circuits/src/evm_circuit.rs b/zkevm-circuits/src/evm_circuit.rs index 12187ff5f7..e4ea39027f 100644 --- a/zkevm-circuits/src/evm_circuit.rs +++ b/zkevm-circuits/src/evm_circuit.rs @@ -13,10 +13,18 @@ pub mod witness; use crate::bytecode_circuit::bytecode_unroller::BytecodeTable; use crate::tx_circuit::TxTable; -use eth_types::Field; +use crate::{ + evm_circuit::{ + util::{rlc, RandomLinearCombination}, + witness::{BlockContext, Bytecode, RwMap, Transaction}, + }, + rw_table::RwTable, +}; +use eth_types::{Field, ToLittleEndian, Word}; use execution::ExecutionConfig; use itertools::Itertools; -use table::{BlockTable, FixedTableTag, LookupTable, TableColumns}; +use keccak256::plain::Keccak; +use table::{BlockTable, FixedTableTag, KeccakTable, LookupTable, TableColumns}; use witness::Block; /// EvmCircuit implements verification of execution trace of a block. @@ -141,17 +149,7 @@ impl EvmCircuit { } } -use crate::{ - evm_circuit::witness::{BlockContext, Bytecode, RwMap, Transaction}, - rw_table::RwTable, -}; - -// TODO: Define a table type for each table, kept in an upper level crate. - -// TODO: Move these load functions to each specific circuit, and import them -// into the EVM circuit. These functions look really clean, so maybe we can -// replace the specific circuit loader by these? - +// TODO: Move to src/tables.rs pub fn load_txs( tx_table: &TxTable, layouter: &mut impl Layouter, @@ -195,6 +193,7 @@ pub fn load_txs( ) } +// TODO: Move to src/tables.rs pub fn load_rws( rw_table: &RwTable, layouter: &mut impl Layouter, @@ -228,15 +227,16 @@ pub fn load_rws( ) } -// use crate::util::TableShow; +use crate::util::TableShow; +// TODO: Move to src/tables.rs pub fn load_bytecodes( bytecode_table: &BytecodeTable, layouter: &mut impl Layouter, bytecodes: &[Bytecode], randomness: F, ) -> Result<(), Error> { - println!("> load_bytecodes"); + // println!("> load_bytecodes"); // let mut table = TableShow::::new(vec!["codeHash", "tag", "index", // "isCode", "value"]); layouter.assign_region( @@ -275,6 +275,8 @@ pub fn load_bytecodes( }, ) } + +// TODO: Move to src/tables.rs pub fn load_block( block_table: &BlockTable, layouter: &mut impl Layouter, @@ -313,6 +315,66 @@ pub fn load_block( ) } +pub fn keccak_table_assignments(input: &[u8], randomness: F) -> Vec<[F; 4]> { + let input_rlc: F = rlc::value(input, randomness); + let input_len = F::from(input.len() as u64); + let mut keccak = Keccak::default(); + keccak.update(input); + let output = keccak.digest(); + let output_rlc = RandomLinearCombination::::random_linear_combine( + Word::from_big_endian(output.as_slice()).to_le_bytes(), + randomness, + ); + + vec![[F::one(), input_rlc, input_len, output_rlc]] +} + +pub fn load_keccaks( + keccak_table: &KeccakTable, + layouter: &mut impl Layouter, + inputs: &[Vec], + randomness: F, +) -> Result<(), Error> { + println!("> super_circuit.load_keccaks"); + let mut table = TableShow::::new(vec!["is_enabled", "input_rlc", "input_len", "output_rlc"]); + layouter.assign_region( + || "keccak table", + |mut region| { + let mut offset = 0; + for column in keccak_table.columns() { + region.assign_advice( + || "keccak table all-zero row", + column, + offset, + || Ok(F::zero()), + )?; + } + offset += 1; + + let keccak_table_columns = keccak_table.columns(); + for input in inputs.iter() { + println!("+ {:?}", input); + for row in keccak_table_assignments(input, randomness) { + let mut column_index = 0; + for (column, value) in keccak_table_columns.iter().zip_eq(row) { + region.assign_advice( + || format!("keccak table row {}", offset), + *column, + offset, + || Ok(value), + )?; + table.push(column_index, value); + column_index += 1; + } + offset += 1; + } + } + table.print(); + Ok(()) + }, + ) +} + #[cfg(any(feature = "test", test))] pub mod test { use super::*; diff --git a/zkevm-circuits/src/evm_circuit/table.rs b/zkevm-circuits/src/evm_circuit/table.rs index 9162b6f468..f61ed74c77 100644 --- a/zkevm-circuits/src/evm_circuit/table.rs +++ b/zkevm-circuits/src/evm_circuit/table.rs @@ -413,6 +413,7 @@ impl Lookup { } } +// TODO: Move to src/tables.rs #[derive(Clone, Debug)] pub struct BlockTable { pub tag: Column, @@ -436,6 +437,7 @@ impl TableColumns for BlockTable { } } +// TODO: Move to src/tables.rs #[derive(Clone, Debug)] pub struct KeccakTable { pub is_enabled: Column, diff --git a/zkevm-circuits/src/super_circuit.rs b/zkevm-circuits/src/super_circuit.rs index 0f1ec0270b..df7812c9d4 100644 --- a/zkevm-circuits/src/super_circuit.rs +++ b/zkevm-circuits/src/super_circuit.rs @@ -12,7 +12,7 @@ #![allow(missing_docs)] // use halo2_proofs::plonk::*; -use crate::tx_circuit::{sign_verify, TxCircuit, TxCircuitConfig, TxTable}; +use crate::tx_circuit::{self, sign_verify, TxCircuit, TxCircuitConfig, TxTable}; use crate::bytecode_circuit::bytecode_unroller::{ unroll, BytecodeTable, Config as BytecodeConfig, UnrolledBytecode, @@ -21,13 +21,15 @@ use crate::bytecode_circuit::bytecode_unroller::{ use crate::util::Expr; use crate::{ evm_circuit::{ - table::{BlockTable, FixedTableTag, KeccakTable}, + table::{BlockTable, FixedTableTag, KeccakTable, TableColumns}, + util::{rlc, RandomLinearCombination}, witness::Block, - EvmCircuit, {load_block, load_bytecodes, load_rws, load_txs}, + EvmCircuit, {load_block, load_bytecodes, load_keccaks, load_rws, load_txs}, }, rw_table::RwTable, }; -use eth_types::Field; +use eth_types::{Field, ToLittleEndian, Word}; +use gadgets::evm_word::encode; use halo2_proofs::{ arithmetic::CurveAffine, circuit::{Layouter, SimpleFloorPlanner}, @@ -35,6 +37,8 @@ use halo2_proofs::{ plonk::{Advice, Circuit, Column, ConstraintSystem, Error, Expression}, poly::Rotation, }; +use itertools::Itertools; +use keccak256::plain::Keccak; #[derive(Clone)] pub struct SuperCircuitConfig { @@ -179,7 +183,7 @@ impl Circuit .evm_circuit .assign_block_exact(&mut layouter, &self.block)?; // --- Tx Circuit --- - self.tx_circuit.assign(config.tx_circuit, &mut layouter)?; + self.tx_circuit.assign(&config.tx_circuit, &mut layouter)?; // --- Bytecode Circuit --- let bytecodes: Vec> = self .block @@ -196,6 +200,24 @@ impl Circuit &bytecodes, self.block.randomness, )?; + // --- Keccak Table --- + let mut keccak_inputs = Vec::new(); + // Lookups from TxCircuit + keccak_inputs.extend_from_slice(&tx_circuit::keccak_inputs( + &self.tx_circuit.txs, + self.block.context.chain_id.as_u64(), + )?); + // Lookups from BytecodeCircuit + for bytecode in &self.block.bytecodes { + keccak_inputs.push(bytecode.bytes.clone()); + } + // Load Keccak Table + load_keccaks( + &config.keccak_table, + &mut layouter, + &keccak_inputs, + self.block.randomness, + )?; Ok(()) } } @@ -313,10 +335,10 @@ mod super_circuit_tests { }; let prover = MockProver::::run(k, &circuit, instance).unwrap(); prover.verify_par(VerifyConfig { - selectors: true, - gates: true, + selectors: false, + gates: false, lookups: true, - perms: true, + perms: false, }) } diff --git a/zkevm-circuits/src/tx_circuit.rs b/zkevm-circuits/src/tx_circuit.rs index 2c3244454b..e94d52bb15 100644 --- a/zkevm-circuits/src/tx_circuit.rs +++ b/zkevm-circuits/src/tx_circuit.rs @@ -8,7 +8,10 @@ pub mod sign_verify; -use crate::evm_circuit::table::{KeccakTable, TableColumns}; +use crate::evm_circuit::{ + load_keccaks, + table::{KeccakTable, TableColumns}, +}; use crate::impl_expr; use crate::util::{random_linear_combine_word as rlc, Expr}; use eth_types::{ @@ -90,6 +93,20 @@ fn ct_option_ok_or(v: CtOption, err: E) -> Result { Option::::from(v).ok_or(err) } +pub fn keccak_inputs(txs: &[Transaction], chain_id: u64) -> Result>, Error> { + let mut inputs = Vec::new(); + let sign_datas: Vec = txs + .iter() + .map(|tx| tx_to_sign_data(tx, chain_id)) + .try_collect()?; + // Keccak inputs from SignVerify Chip + let sign_verify_inputs = sign_verify::keccak_inputs(&sign_datas); + inputs.extend_from_slice(&sign_verify_inputs); + // NOTE: We don't verify the Tx Hash in the circuit yet, so we don't have more + // hash inputs. + Ok(inputs) +} + fn tx_to_sign_data(tx: &Transaction, chain_id: u64) -> Result { let sig_r_le = tx.r.to_le_bytes(); let sig_s_le = tx.s.to_le_bytes(); @@ -182,6 +199,7 @@ pub struct TxCircuitConfig { index: Column, value: Column, sign_verify: SignVerifyConfig, + keccak_table: KeccakTable, _marker: PhantomData, } @@ -246,7 +264,7 @@ impl TxCircuitConfig { // power_of_randomness.unwrap() // }; - let sign_verify = SignVerifyConfig::new(meta, power_of_randomness, keccak_table); + let sign_verify = SignVerifyConfig::new(meta, power_of_randomness, keccak_table.clone()); Self { tx_id, @@ -254,6 +272,7 @@ impl TxCircuitConfig { index, value, sign_verify, + keccak_table, _marker: PhantomData, } } @@ -312,7 +331,7 @@ impl pub fn assign( &self, - config: TxCircuitConfig, + config: &TxCircuitConfig, layouter: &mut impl Layouter, ) -> Result<(), Error> { assert!(self.txs.len() <= MAX_TXS); @@ -500,7 +519,13 @@ impl Circuit config: Self::Config, mut layouter: impl Layouter, ) -> Result<(), Error> { - self.assign(config, &mut layouter) + self.assign(&config, &mut layouter)?; + load_keccaks( + &config.keccak_table, + &mut layouter, + &keccak_inputs(&self.txs, self.chain_id)?, + self.randomness, + ) } } diff --git a/zkevm-circuits/src/tx_circuit/sign_verify.rs b/zkevm-circuits/src/tx_circuit/sign_verify.rs index 4756432c11..c551ab8e53 100644 --- a/zkevm-circuits/src/tx_circuit/sign_verify.rs +++ b/zkevm-circuits/src/tx_circuit/sign_verify.rs @@ -6,6 +6,7 @@ use crate::{ evm_circuit::{ + load_keccaks, table::KeccakTable, util::{not, RandomLinearCombination, Word}, }, @@ -13,7 +14,7 @@ use crate::{ }; use ecc::{EccConfig, GeneralEccChip}; use ecdsa::ecdsa::{AssignedEcdsaSig, AssignedPublicKey, EcdsaChip}; -use eth_types::Field; +use eth_types::{self, Field, ToLittleEndian}; use gadgets::is_zero::{IsZeroChip, IsZeroConfig, IsZeroInstruction}; use group::{ff::Field as GroupField, prime::PrimeCurveAffine, Curve}; use halo2_proofs::{ @@ -74,6 +75,36 @@ pub(crate) fn pk_bytes_swap_endianness(pk: &[T]) -> [T; 64] { pk_swap } +pub(crate) fn pk_bytes_le(pk: &Secp256k1Affine) -> [u8; 64] { + let pk_coord = Option::>::from(pk.coordinates()).expect("point is the identity"); + let mut pk_le = [0u8; 64]; + pk_coord + .x() + .write(&mut Cursor::new(&mut pk_le[..32])) + .expect("cannot write bytes to array"); + pk_coord + .y() + .write(&mut Cursor::new(&mut pk_le[32..])) + .expect("cannot write bytes to array"); + pk_le +} + +// CHANGELOG: Add function to obtain all the keccak inputs required by the +// SignVerifyChip +pub(crate) fn keccak_inputs(sigs: &[SignData]) -> Vec> { + let mut inputs = Vec::new(); + for sig in sigs { + let pk_le = pk_bytes_le(&sig.pk); + let pk_be = pk_bytes_swap_endianness(&pk_le); + inputs.push(pk_be.to_vec()); + } + // Padding signature + let pk_le = pk_bytes_le(&SignData::default().pk); + let pk_be = pk_bytes_swap_endianness(&pk_le); + inputs.push(pk_be.to_vec()); + inputs +} + /// Return an expression that builds an integer element in the field from the /// `bytes` in big endian. fn int_from_bytes_be(bytes: &[Expression]) -> Expression { @@ -198,9 +229,15 @@ impl SignVerifyConfig { // Column 3: output_rlc (pk_hash_rlc) let keccak_output_rlc = meta.query_advice(keccak_table.output_rlc, Rotation::cur()); - let pk_hash = pk_hash.map(|c| meta.query_advice(c, Rotation::cur())); - let pk_hash_rlc = - RandomLinearCombination::random_linear_combine_expr(pk_hash, &power_of_randomness); + let mut pk_hash_rev = pk_hash.map(|c| meta.query_advice(c, Rotation::cur())); + // CHANGELOG: Reverse the pk_hash used in the lookup so that the RLC is + // calculated as if it was a hash in an Ethereum Word. + pk_hash_rev.reverse(); // Ethereum decodes pk_hash into a Word as big endian, but + // `random_linear_combine_expr` expects LSB first. + let pk_hash_rlc = RandomLinearCombination::random_linear_combine_expr( + pk_hash_rev, + &power_of_randomness, + ); table_map.push((selector * pk_hash_rlc, keccak_output_rlc)); table_map @@ -263,6 +300,8 @@ pub(crate) struct KeccakAux { output: [u8; 32], } +use crate::util::TableShow; + impl SignVerifyConfig { pub(crate) fn load_range(&self, layouter: &mut impl Layouter) -> Result<(), Error> { let bit_len_lookup = BIT_LEN_LIMB / NUMBER_OF_LOOKUP_LIMBS; @@ -317,11 +356,18 @@ impl SignVerifyConfig { self.keccak_assign_row(&mut region, offset, F::zero(), F::zero(), 0, F::zero())?; offset += 1; + println!("> sign_verify.load_keccak"); + let mut table = + TableShow::::new(vec!["is_enabled", "input_rlc", "input_len", "output_rlc"]); + for aux in &auxs { let KeccakAux { input, output } = aux; let input_rlc = RandomLinearCombination::random_linear_combine(*input, randomness); - let output_rlc = Word::random_linear_combine(*output, randomness); + let output_rlc = Word::random_linear_combine( + eth_types::Word::from_big_endian(output.as_slice()).to_le_bytes(), + randomness, + ); self.keccak_assign_row( &mut region, offset, @@ -331,7 +377,12 @@ impl SignVerifyConfig { output_rlc, )?; offset += 1; + table.push(0, F::one()); + table.push(1, input_rlc); + table.push(2, F::from(input.len() as u64)); + table.push(3, output_rlc); } + table.print(); Ok(()) }, )?; @@ -553,19 +604,8 @@ impl SignVerifyChip { )?; // Assign pk - let pk_coord = - Option::>::from(pk.coordinates()).expect("point is the identity"); - let mut pk_x_le = [0u8; 32]; - let mut pk_y_le = [0u8; 32]; - pk_coord - .x() - .write(&mut Cursor::new(&mut pk_x_le[..])) - .expect("cannot write bytes to array"); - pk_coord - .y() - .write(&mut Cursor::new(&mut pk_y_le[..])) - .expect("cannot write bytes to array"); - for (i, byte) in pk_x_le.iter().enumerate() { + let pk_le = pk_bytes_le(&pk); + for (i, byte) in pk_le[..32].iter().enumerate() { region.assign_advice( || format!("pk x byte {}", i), config.pk[0][i], @@ -573,7 +613,7 @@ impl SignVerifyChip { || Ok(F::from(*byte as u64)), )?; } - for (i, byte) in pk_y_le.iter().enumerate() { + for (i, byte) in pk_le[32..].iter().enumerate() { region.assign_advice( || format!("pk y byte {}", i), config.pk[1][i], @@ -582,9 +622,6 @@ impl SignVerifyChip { )?; } - let mut pk_le = [0u8; 64]; - pk_le[..32].copy_from_slice(&pk_x_le); - pk_le[32..].copy_from_slice(&pk_y_le); let pk_be = pk_bytes_swap_endianness(&pk_le); let mut keccak = Keccak::default(); keccak.update(&pk_be); @@ -721,7 +758,7 @@ impl SignVerifyChip { }, )?; - config.load_keccak(layouter, keccak_auxs, randomness)?; + // config.load_keccak(layouter, keccak_auxs, randomness)?; config.load_range(layouter)?; Ok(assigned_sig_verifs) @@ -867,6 +904,12 @@ mod sign_verify_tests { self.randomness, &self.signatures, )?; + load_keccaks( + &config.sign_verify.keccak_table, + &mut layouter, + &keccak_inputs(&self.signatures), + self.randomness, + ); Ok(()) } } From a4be2b649d15f2984930f4f1784d3a1ec81f4b34 Mon Sep 17 00:00:00 2001 From: Eduard S Date: Fri, 15 Jul 2022 10:47:16 +0200 Subject: [PATCH 12/26] WIP --- .../src/bytecode_circuit/bytecode_unroller.rs | 7 ++- zkevm-circuits/src/evm_circuit.rs | 7 ++- zkevm-circuits/src/evm_circuit/util.rs | 8 ++++ zkevm-circuits/src/super_circuit.rs | 43 ++++++++++++++++++- zkevm-circuits/src/tx_circuit/sign_verify.rs | 3 +- 5 files changed, 61 insertions(+), 7 deletions(-) diff --git a/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs b/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs index 6852eff6d2..4da6a6ca61 100644 --- a/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs +++ b/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs @@ -635,9 +635,8 @@ impl Config { |mut region| { for (offset, bytecode) in bytecodes.iter().map(|v| v.bytes.clone()).enumerate() { let code_hash: F = keccak(&bytecode[..], randomness); - println!("+ {:?}", bytecode); - // CHANGELOG: Fixed rlc of input in the correct order. - let input_rlc: F = rlc::value(&bytecode, randomness); + // println!("+ {:?}", bytecode); + let input_rlc: F = rlc::value_from_iter(bytecode.iter().rev(), randomness); let size = F::from(bytecode.len() as u64); for (name, column, value) in &[ ("is_enable", self.keccak_table.is_enabled, F::one()), @@ -695,7 +694,7 @@ impl Config { }, )?; // TODO: Remove this - self.load_keccaks(layouter, bytecodes, randomness)?; + // self.load_keccaks(layouter, bytecodes, randomness)?; Ok(()) } diff --git a/zkevm-circuits/src/evm_circuit.rs b/zkevm-circuits/src/evm_circuit.rs index e4ea39027f..643c28c4f3 100644 --- a/zkevm-circuits/src/evm_circuit.rs +++ b/zkevm-circuits/src/evm_circuit.rs @@ -316,7 +316,8 @@ pub fn load_block( } pub fn keccak_table_assignments(input: &[u8], randomness: F) -> Vec<[F; 4]> { - let input_rlc: F = rlc::value(input, randomness); + // CHANGELOG: Using `RLC(reversed(input))` + let input_rlc: F = rlc::value_from_iter(input.iter().rev(), randomness); let input_len = F::from(input.len() as u64); let mut keccak = Keccak::default(); keccak.update(input); @@ -329,6 +330,10 @@ pub fn keccak_table_assignments(input: &[u8], randomness: F) -> Vec<[F vec![[F::one(), input_rlc, input_len, output_rlc]] } +// NOTE: For now, the input_rlc of the keccak is defined as +// `RLC(reversed(input))` for convenience of the circuits that do the lookups. +// This allows calculating the `input_rlc` after all the inputs bytes have been +// layed out via the pattern `acc[i] = acc[i-1] * r + value[i]`. pub fn load_keccaks( keccak_table: &KeccakTable, layouter: &mut impl Layouter, diff --git a/zkevm-circuits/src/evm_circuit/util.rs b/zkevm-circuits/src/evm_circuit/util.rs index 2ab26bdebb..8cf1d802dd 100644 --- a/zkevm-circuits/src/evm_circuit/util.rs +++ b/zkevm-circuits/src/evm_circuit/util.rs @@ -412,6 +412,14 @@ pub(crate) mod rlc { acc * randomness + F::from(*value as u64) }) } + pub(crate) fn value_from_iter<'a, F: FieldExt, I>(values: I, randomness: F) -> F + where + I: Iterator + std::iter::DoubleEndedIterator, + { + values.rev().fold(F::zero(), |acc, value| { + acc * randomness + F::from(*value as u64) + }) + } } /// Returns 2**by as FieldExt diff --git a/zkevm-circuits/src/super_circuit.rs b/zkevm-circuits/src/super_circuit.rs index df7812c9d4..fd1c454c82 100644 --- a/zkevm-circuits/src/super_circuit.rs +++ b/zkevm-circuits/src/super_circuit.rs @@ -40,9 +40,50 @@ use halo2_proofs::{ use itertools::Itertools; use keccak256::plain::Keccak; +// The SuperCircuit contains the following circuits: +// +// - [x] EVM Circuit +// - [ ] State Circuit +// - [x] Tx Circuit +// - [x] Bytecode Circuit +// - [ ] Copy Circuit +// - [ ] Keccak Circuit +// - [ ] MPT Circuit +// - [ ] PublicInputs Circuit +// +// And the following shared tables, with the circuits that use them: +// +// - [ ] Copy Table +// - [ ] Copy Circuit +// - [ ] EVM Circuit +// - [ ] Rw Table +// - [ ] State Circuit +// - [ ] EVM Circuit +// - [ ] Copy Circuit +// - [x] Tx Table +// - [x] Tx Circuit +// - [x] EVM Circuit +// - [ ] Copy Circuit +// - [ ] PublicInputs Circuit +// - [x] Bytecode Table +// - [x] Bytecode Circuit +// - [x] EVM Circuit +// - [ ] Copy Circuit +// - [ ] Block Table +// - [ ] EVM Circuit +// - [ ] PublicInputs Circuit +// - [ ] MPT Table +// - [ ] MPT Circuit +// - [ ] State Circuit +// - [x] Keccak Table +// - [ ] Keccak Circuit +// - [ ] EVM Circuit +// - [x] Bytecode Circuit +// - [x] Tx Circuit +// - [ ] MPT Circuit + #[derive(Clone)] pub struct SuperCircuitConfig { - // tx_table: [Column; 4], tx_table: TxTable, rw_table: RwTable, bytecode_table: BytecodeTable, diff --git a/zkevm-circuits/src/tx_circuit/sign_verify.rs b/zkevm-circuits/src/tx_circuit/sign_verify.rs index c551ab8e53..108ed9b645 100644 --- a/zkevm-circuits/src/tx_circuit/sign_verify.rs +++ b/zkevm-circuits/src/tx_circuit/sign_verify.rs @@ -218,7 +218,8 @@ impl SignVerifyConfig { .collect::>>() .try_into() .expect("vector to array of size 64"); - let pk_be = pk_bytes_swap_endianness(&pk_le); + let mut pk_be = pk_bytes_swap_endianness(&pk_le); + pk_be.reverse(); let pk_rlc = RandomLinearCombination::random_linear_combine_expr(pk_be, &power_of_randomness); table_map.push((selector.clone() * pk_rlc, keccak_input_rlc)); From e738148e33df9be7bcb5aa813cb73d536263e069 Mon Sep 17 00:00:00 2001 From: Eduard S Date: Fri, 15 Jul 2022 11:42:46 +0200 Subject: [PATCH 13/26] WIP --- Cargo.toml | 4 ++-- gadgets/src/util.rs | 4 ++-- zkevm-circuits/src/evm_circuit.rs | 20 +++++++++++++------- zkevm-circuits/src/super_circuit.rs | 6 +++--- 4 files changed, 20 insertions(+), 14 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d4e1b060dd..7a75a713cd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,5 +43,5 @@ debug = false debug-assertions = true overflow-checks = true rpath = false -# lto = "thin" -# incremental = false +# lto = "thin" # TODO: Uncomment when the PR is ready to review +# incremental = false # TODO: Uncomment when the PR is ready to review diff --git a/gadgets/src/util.rs b/gadgets/src/util.rs index 755381871a..7ae95c702d 100644 --- a/gadgets/src/util.rs +++ b/gadgets/src/util.rs @@ -126,7 +126,7 @@ pub trait Expr { #[macro_export] macro_rules! impl_expr { ($type:ty) => { - impl $crate::util::Expr for $type { + impl $crate::util::Expr for $type { #[inline] fn expr(&self) -> Expression { Expression::Constant(F::from(*self as u64)) @@ -134,7 +134,7 @@ macro_rules! impl_expr { } }; ($type:ty, $method:path) => { - impl $crate::util::Expr for $type { + impl $crate::util::Expr for $type { #[inline] fn expr(&self) -> Expression { Expression::Constant(F::from($method(self) as u64)) diff --git a/zkevm-circuits/src/evm_circuit.rs b/zkevm-circuits/src/evm_circuit.rs index 643c28c4f3..45eb23bd77 100644 --- a/zkevm-circuits/src/evm_circuit.rs +++ b/zkevm-circuits/src/evm_circuit.rs @@ -441,7 +441,7 @@ pub mod test { || "tx table", |mut region| { let mut offset = 0; - for column in self.tx_table { + for column in self.tx_table.columns() { region.assign_advice( || "tx table all-zero row", column, @@ -453,7 +453,7 @@ pub mod test { for tx in txs.iter() { for row in tx.table_assignments(randomness) { - for (column, value) in self.tx_table.iter().zip_eq(row) { + for (column, value) in self.tx_table.columns().iter().zip_eq(row) { region.assign_advice( || format!("tx table row {}", offset), *column, @@ -517,7 +517,7 @@ pub mod test { || "bytecode table", |mut region| { let mut offset = 0; - for column in self.bytecode_table { + for column in self.bytecode_table.columns() { region.assign_advice( || "bytecode table all-zero row", column, @@ -529,7 +529,8 @@ pub mod test { for bytecode in bytecodes.clone() { for row in bytecode.table_assignments(randomness) { - for (column, value) in self.bytecode_table.iter().zip_eq(row) { + for (column, value) in self.bytecode_table.columns().iter().zip_eq(row) + { region.assign_advice( || format!("bytecode table row {}", offset), *column, @@ -555,7 +556,7 @@ pub mod test { || "block table", |mut region| { let mut offset = 0; - for column in self.block_table { + for column in self.block_table.columns() { region.assign_advice( || "block table all-zero row", column, @@ -566,7 +567,7 @@ pub mod test { offset += 1; for row in block.table_assignments(randomness) { - for (column, value) in self.block_table.iter().zip_eq(row) { + for (column, value) in self.block_table.columns().iter().zip_eq(row) { region.assign_advice( || format!("block table row {}", offset), *column, @@ -681,7 +682,12 @@ pub mod test { load_bytecodes( &config.bytecode_table, &mut layouter, - &self.block.bytecodes, + &self + .block + .bytecodes + .iter() + .map(|(_, b)| b.clone()) + .collect::>(), self.block.randomness, )?; load_block( diff --git a/zkevm-circuits/src/super_circuit.rs b/zkevm-circuits/src/super_circuit.rs index fd1c454c82..4fde0cb53f 100644 --- a/zkevm-circuits/src/super_circuit.rs +++ b/zkevm-circuits/src/super_circuit.rs @@ -230,7 +230,7 @@ impl Circuit .block .bytecodes .iter() - .map(|b| unroll(b.bytes.clone(), self.block.randomness)) + .map(|(_, b)| unroll(b.bytes.clone(), self.block.randomness)) .collect(); config .bytecode_circuit @@ -249,7 +249,7 @@ impl Circuit self.block.context.chain_id.as_u64(), )?); // Lookups from BytecodeCircuit - for bytecode in &self.block.bytecodes { + for (_, bytecode) in &self.block.bytecodes { keccak_inputs.push(bytecode.bytes.clone()); } // Load Keccak Table @@ -352,7 +352,7 @@ mod super_circuit_tests { let bytecodes_len = block .bytecodes .iter() - .map(|bytecode| bytecode.bytes.len()) + .map(|(_, bytecode)| bytecode.bytes.len()) .sum::(); let k = k.max(log2_ceil(64 + bytecodes_len)); let k = k.max(log2_ceil(64 + num_rows_required_for_steps)); From e25931c7059fed7ad626c7f2aadc886dfd18c60e Mon Sep 17 00:00:00 2001 From: Eduard S Date: Fri, 15 Jul 2022 14:35:24 +0200 Subject: [PATCH 14/26] Do some clean ups --- .../src/bytecode_circuit/bytecode_unroller.rs | 124 +++++------ zkevm-circuits/src/evm_circuit.rs | 205 ++---------------- zkevm-circuits/src/evm_circuit/util.rs | 17 +- zkevm-circuits/src/evm_circuit/witness.rs | 1 - zkevm-circuits/src/rw_table.rs | 3 +- .../state_circuit/lexicographic_ordering.rs | 1 - zkevm-circuits/src/super_circuit.rs | 19 +- zkevm-circuits/src/tx_circuit.rs | 6 +- zkevm-circuits/src/tx_circuit/sign_verify.rs | 4 +- 9 files changed, 96 insertions(+), 284 deletions(-) diff --git a/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs b/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs index 4da6a6ca61..4d83f20cfc 100644 --- a/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs +++ b/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs @@ -1,5 +1,6 @@ use crate::{ evm_circuit::{ + load_keccaks, table::{BytecodeFieldTag, KeccakTable, TableColumns}, util::{ and, constraint_builder::BaseConstraintBuilder, not, or, rlc, select, @@ -15,17 +16,16 @@ use gadgets::{ is_zero::{IsZeroChip, IsZeroConfig, IsZeroInstruction}, }; use halo2_proofs::{ - arithmetic::FieldExt, circuit::{Layouter, Region}, plonk::{Advice, Column, ConstraintSystem, Error, Expression, Fixed, Selector, VirtualCells}, poly::Rotation, }; use keccak256::plain::Keccak; -use std::{convert::TryInto, vec}; +use std::vec; // use crate::util::TableShow; -use super::param::{KECCAK_WIDTH, PUSH_TABLE_WIDTH}; +use super::param::PUSH_TABLE_WIDTH; /// Public data for the bytecode #[derive(Clone, Debug, PartialEq)] @@ -113,10 +113,6 @@ impl Config { let q_enable = meta.fixed_column(); let q_first = meta.fixed_column(); let q_last = meta.selector(); - // let code_hash = bytecode_table.code_hash; - // let tag = bytecode_table.tag; - // let index = bytecode_table.index; - // let is_code = bytecode_table.is_code; let value = bytecode_table.value; let push_rindex = meta.advice_column(); let hash_input_rlc = meta.advice_column(); @@ -453,7 +449,7 @@ impl Config { |mut region| { let mut offset = 0; let mut push_rindex_prev = 0; - println!("> BytecodeConfig::assign"); + // println!("> BytecodeConfig::assign"); // let mut table = // TableShow::::new(vec!["codeHash", "tag", "index", "isCode", "value"]); @@ -621,54 +617,49 @@ impl Config { // CHANGELOG: Moved to a new function to allow not calling it when integrating // circuits together. - pub(crate) fn load_keccaks( - &self, - layouter: &mut impl Layouter, - bytecodes: &[UnrolledBytecode], - randomness: F, - ) -> Result<(), Error> { - println!("> bytecode_circuit.load_keccaks"); - let mut table = - TableShow::::new(vec!["is_enabled", "input_rlc", "input_len", "output_rlc"]); - layouter.assign_region( - || "keccak table", - |mut region| { - for (offset, bytecode) in bytecodes.iter().map(|v| v.bytes.clone()).enumerate() { - let code_hash: F = keccak(&bytecode[..], randomness); - // println!("+ {:?}", bytecode); - let input_rlc: F = rlc::value_from_iter(bytecode.iter().rev(), randomness); - let size = F::from(bytecode.len() as u64); - for (name, column, value) in &[ - ("is_enable", self.keccak_table.is_enabled, F::one()), - ("input_rlc", self.keccak_table.input_rlc, input_rlc), - ("input_len", self.keccak_table.input_len, size), - ("output_rlc", self.keccak_table.output_rlc, code_hash), - ] { - region.assign_advice( - || format!("Keccak table assign {} {}", name, offset), - *column, - offset, - || Ok(*value), - )?; - } - table.push(0, F::one()); - table.push(1, input_rlc); - table.push(2, size); - table.push(3, code_hash); - } - table.print(); - Ok(()) - }, - ) - } + // pub(crate) fn load_keccaks( + // &self, + // layouter: &mut impl Layouter, + // bytecodes: &[UnrolledBytecode], + // randomness: F, + // ) -> Result<(), Error> { + // println!("> bytecode_circuit.load_keccaks"); + // let mut table = + // TableShow::::new(vec!["is_enabled", "input_rlc", "input_len", + // "output_rlc"]); layouter.assign_region( + // || "keccak table", + // |mut region| { + // for (offset, bytecode) in bytecodes.iter().map(|v| + // v.bytes.clone()).enumerate() { let code_hash: F = + // keccak(&bytecode[..], randomness); // println!("+ {:?}", + // bytecode); let input_rlc: F = + // rlc::value(bytecode.iter().rev(), randomness); let size = + // F::from(bytecode.len() as u64); for (name, column, value) + // in &[ ("is_enable", self.keccak_table.is_enabled, + // F::one()), ("input_rlc", self.keccak_table.input_rlc, + // input_rlc), ("input_len", + // self.keccak_table.input_len, size), ("output_rlc", + // self.keccak_table.output_rlc, code_hash), ] { + // region.assign_advice( + // || format!("Keccak table assign {} {}", name, + // offset), *column, + // offset, + // || Ok(*value), + // )?; + // } + // table.push(0, F::one()); + // table.push(1, input_rlc); + // table.push(2, size); + // table.push(3, code_hash); + // } + // table.print(); + // Ok(()) + // }, + // ) + // } - /// load tables - pub(crate) fn load( - &self, - layouter: &mut impl Layouter, - bytecodes: &[UnrolledBytecode], - randomness: F, - ) -> Result<(), Error> { + /// load fixed tables + pub(crate) fn load(&self, layouter: &mut impl Layouter) -> Result<(), Error> { // push table: BYTE -> NUM_PUSHED: // [0, OpcodeId::PUSH1[ -> 0 // [OpcodeId::PUSH1, OpcodeId::PUSH32] -> [1..32] @@ -693,8 +684,6 @@ impl Config { Ok(()) }, )?; - // TODO: Remove this - // self.load_keccaks(layouter, bytecodes, randomness)?; Ok(()) } @@ -766,10 +755,6 @@ fn into_words(message: &[u8]) -> Vec { words } -fn linear_combine(bytes: Vec, randomness: F) -> F { - encode(bytes.into_iter(), randomness) -} - #[cfg(test)] mod tests { use super::*; @@ -788,11 +773,6 @@ mod tests { randomness: F, } - // impl MyCircuit { - // fn randomness() -> F { - // F::from(123456) - // } - // } fn get_randomness() -> F { F::from(123456) } @@ -839,8 +819,13 @@ mod tests { config: Self::Config, mut layouter: impl Layouter, ) -> Result<(), Error> { - config.load(&mut layouter, &self.bytecodes, self.randomness)?; - config.load_keccaks(&mut layouter, &self.bytecodes, self.randomness)?; + config.load(&mut layouter)?; + load_keccaks( + &config.keccak_table, + &mut layouter, + self.bytecodes.iter().map(|b| b.bytes.as_slice()), + self.randomness, + )?; config.assign(&mut layouter, self.size, &self.bytecodes, self.randomness)?; Ok(()) } @@ -853,7 +838,8 @@ mod tests { randomness, }; - let prover = MockProver::::run(k, &circuit, vec![]).unwrap(); + let instance = vec![vec![randomness; (1 << k) - 7 + 1]]; + let prover = MockProver::::run(k, &circuit, instance).unwrap(); let err = prover.verify(); let print_failures = true; if err.is_err() && print_failures { diff --git a/zkevm-circuits/src/evm_circuit.rs b/zkevm-circuits/src/evm_circuit.rs index 45eb23bd77..1e20c22b49 100644 --- a/zkevm-circuits/src/evm_circuit.rs +++ b/zkevm-circuits/src/evm_circuit.rs @@ -230,10 +230,10 @@ pub fn load_rws( use crate::util::TableShow; // TODO: Move to src/tables.rs -pub fn load_bytecodes( +pub fn load_bytecodes<'a, F: Field>( bytecode_table: &BytecodeTable, layouter: &mut impl Layouter, - bytecodes: &[Bytecode], + bytecodes: impl IntoIterator + Clone, randomness: F, ) -> Result<(), Error> { // println!("> load_bytecodes"); @@ -254,9 +254,9 @@ pub fn load_bytecodes( offset += 1; let bytecode_table_columns = bytecode_table.columns(); - for bytecode in bytecodes.iter() { + for bytecode in bytecodes.clone() { for row in bytecode.table_assignments(randomness) { - let mut column_index = 0; + // let mut column_index = 0; for (column, value) in bytecode_table_columns.iter().zip_eq(row) { region.assign_advice( || format!("bytecode table row {}", offset), @@ -265,7 +265,7 @@ pub fn load_bytecodes( || Ok(value), )?; // table.push(column_index, value); - column_index += 1; + // column_index += 1; } offset += 1; } @@ -317,7 +317,7 @@ pub fn load_block( pub fn keccak_table_assignments(input: &[u8], randomness: F) -> Vec<[F; 4]> { // CHANGELOG: Using `RLC(reversed(input))` - let input_rlc: F = rlc::value_from_iter(input.iter().rev(), randomness); + let input_rlc: F = rlc::value(input.iter().rev(), randomness); let input_len = F::from(input.len() as u64); let mut keccak = Keccak::default(); keccak.update(input); @@ -334,14 +334,15 @@ pub fn keccak_table_assignments(input: &[u8], randomness: F) -> Vec<[F // `RLC(reversed(input))` for convenience of the circuits that do the lookups. // This allows calculating the `input_rlc` after all the inputs bytes have been // layed out via the pattern `acc[i] = acc[i-1] * r + value[i]`. -pub fn load_keccaks( +pub fn load_keccaks<'a, F: Field>( keccak_table: &KeccakTable, layouter: &mut impl Layouter, - inputs: &[Vec], + inputs: impl IntoIterator + Clone, randomness: F, ) -> Result<(), Error> { - println!("> super_circuit.load_keccaks"); - let mut table = TableShow::::new(vec!["is_enabled", "input_rlc", "input_len", "output_rlc"]); + // println!("> super_circuit.load_keccaks"); + // let mut table = TableShow::::new(vec!["is_enabled", "input_rlc", + // "input_len", "output_rlc"]); layouter.assign_region( || "keccak table", |mut region| { @@ -357,10 +358,10 @@ pub fn load_keccaks( offset += 1; let keccak_table_columns = keccak_table.columns(); - for input in inputs.iter() { - println!("+ {:?}", input); + for input in inputs.clone() { + // println!("+ {:?}", input); for row in keccak_table_assignments(input, randomness) { - let mut column_index = 0; + // let mut column_index = 0; for (column, value) in keccak_table_columns.iter().zip_eq(row) { region.assign_advice( || format!("keccak table row {}", offset), @@ -368,13 +369,13 @@ pub fn load_keccaks( offset, || Ok(value), )?; - table.push(column_index, value); - column_index += 1; + // table.push(column_index, value); + // column_index += 1; } offset += 1; } } - table.print(); + // table.print(); Ok(()) }, ) @@ -392,7 +393,7 @@ pub mod test { use halo2_proofs::{ circuit::{Layouter, SimpleFloorPlanner}, dev::{MockProver, VerifyFailure}, - plonk::{Advice, Circuit, Column, ConstraintSystem, Error}, + plonk::{Circuit, ConstraintSystem, Error}, poly::Rotation, }; use rand::{ @@ -430,160 +431,6 @@ pub mod test { evm_circuit: EvmCircuit, } - impl TestCircuitConfig { - fn load_txs( - &self, - layouter: &mut impl Layouter, - txs: &[Transaction], - randomness: F, - ) -> Result<(), Error> { - layouter.assign_region( - || "tx table", - |mut region| { - let mut offset = 0; - for column in self.tx_table.columns() { - region.assign_advice( - || "tx table all-zero row", - column, - offset, - || Ok(F::zero()), - )?; - } - offset += 1; - - for tx in txs.iter() { - for row in tx.table_assignments(randomness) { - for (column, value) in self.tx_table.columns().iter().zip_eq(row) { - region.assign_advice( - || format!("tx table row {}", offset), - *column, - offset, - || Ok(value), - )?; - } - offset += 1; - } - } - Ok(()) - }, - ) - } - - fn load_rws( - &self, - layouter: &mut impl Layouter, - rws: &RwMap, - randomness: F, - ) -> Result<(), Error> { - layouter.assign_region( - || "rw table", - |mut region| { - let mut offset = 0; - self.rw_table - .assign(&mut region, offset, &Default::default())?; - offset += 1; - - let mut rows = rws - .0 - .values() - .flat_map(|rws| rws.iter()) - .collect::>(); - - rows.sort_by_key(|a| a.rw_counter()); - let mut expected_rw_counter = 1; - for rw in rows { - assert!(rw.rw_counter() == expected_rw_counter); - expected_rw_counter += 1; - - self.rw_table.assign( - &mut region, - offset, - &rw.table_assignment(randomness), - )?; - offset += 1; - } - Ok(()) - }, - ) - } - - fn load_bytecodes<'a>( - &self, - layouter: &mut impl Layouter, - bytecodes: impl IntoIterator + Clone, - randomness: F, - ) -> Result<(), Error> { - layouter.assign_region( - || "bytecode table", - |mut region| { - let mut offset = 0; - for column in self.bytecode_table.columns() { - region.assign_advice( - || "bytecode table all-zero row", - column, - offset, - || Ok(F::zero()), - )?; - } - offset += 1; - - for bytecode in bytecodes.clone() { - for row in bytecode.table_assignments(randomness) { - for (column, value) in self.bytecode_table.columns().iter().zip_eq(row) - { - region.assign_advice( - || format!("bytecode table row {}", offset), - *column, - offset, - || Ok(value), - )?; - } - offset += 1; - } - } - Ok(()) - }, - ) - } - - fn load_block( - &self, - layouter: &mut impl Layouter, - block: &BlockContext, - randomness: F, - ) -> Result<(), Error> { - layouter.assign_region( - || "block table", - |mut region| { - let mut offset = 0; - for column in self.block_table.columns() { - region.assign_advice( - || "block table all-zero row", - column, - offset, - || Ok(F::zero()), - )?; - } - offset += 1; - - for row in block.table_assignments(randomness) { - for (column, value) in self.block_table.columns().iter().zip_eq(row) { - region.assign_advice( - || format!("block table row {}", offset), - *column, - offset, - || Ok(value), - )?; - } - offset += 1; - } - - Ok(()) - }, - ) - } - } - #[derive(Default)] pub struct TestCircuit { block: Block, @@ -658,15 +505,6 @@ pub mod test { .evm_circuit .load_fixed_table(&mut layouter, self.fixed_table_tags.clone())?; config.evm_circuit.load_byte_table(&mut layouter)?; - // config.load_txs(&mut layouter, &self.block.txs, self.block.randomness)?; - // config.load_rws(&mut layouter, &self.block.rws, self.block.randomness)?; - // config.load_bytecodes( - // &mut layouter, - // self.block.bytecodes.values(), - // self.block.randomness, - // )?; - // config.load_block(&mut layouter, &self.block.context, - // self.block.randomness)?; load_txs( &config.tx_table, &mut layouter, @@ -682,12 +520,7 @@ pub mod test { load_bytecodes( &config.bytecode_table, &mut layouter, - &self - .block - .bytecodes - .iter() - .map(|(_, b)| b.clone()) - .collect::>(), + self.block.bytecodes.iter().map(|(_, b)| b), self.block.randomness, )?; load_block( diff --git a/zkevm-circuits/src/evm_circuit/util.rs b/zkevm-circuits/src/evm_circuit/util.rs index 8cf1d802dd..0a2f14aeb6 100644 --- a/zkevm-circuits/src/evm_circuit/util.rs +++ b/zkevm-circuits/src/evm_circuit/util.rs @@ -407,16 +407,17 @@ pub(crate) mod rlc { rlc } - pub(crate) fn value(values: &[u8], randomness: F) -> F { - values.iter().rev().fold(F::zero(), |acc, value| { - acc * randomness + F::from(*value as u64) - }) - } - pub(crate) fn value_from_iter<'a, F: FieldExt, I>(values: I, randomness: F) -> F + // pub(crate) fn value(values: &[u8], randomness: F) -> F { + // values.iter().rev().fold(F::zero(), |acc, value| { + // acc * randomness + F::from(*value as u64) + // }) + // } + pub(crate) fn value<'a, F: FieldExt, I>(values: I, randomness: F) -> F where - I: Iterator + std::iter::DoubleEndedIterator, + I: IntoIterator, + ::IntoIter: DoubleEndedIterator, { - values.rev().fold(F::zero(), |acc, value| { + values.into_iter().rev().fold(F::zero(), |acc, value| { acc * randomness + F::from(*value as u64) }) } diff --git a/zkevm-circuits/src/evm_circuit/witness.rs b/zkevm-circuits/src/evm_circuit/witness.rs index 83a0d6a946..835920f843 100644 --- a/zkevm-circuits/src/evm_circuit/witness.rs +++ b/zkevm-circuits/src/evm_circuit/witness.rs @@ -1264,7 +1264,6 @@ impl From<&circuit_input_builder::ExecStep> for ExecutionState { OpcodeId::CODESIZE => ExecutionState::CODESIZE, OpcodeId::RETURN | OpcodeId::REVERT => ExecutionState::RETURN, // dummy ops - OpcodeId::SHA3 => dummy!(ExecutionState::SHA3), OpcodeId::ADDRESS => dummy!(ExecutionState::ADDRESS), OpcodeId::BALANCE => dummy!(ExecutionState::BALANCE), OpcodeId::BLOCKHASH => dummy!(ExecutionState::BLOCKHASH), diff --git a/zkevm-circuits/src/rw_table.rs b/zkevm-circuits/src/rw_table.rs index e1f7c261f5..9099ba823e 100644 --- a/zkevm-circuits/src/rw_table.rs +++ b/zkevm-circuits/src/rw_table.rs @@ -2,8 +2,7 @@ use halo2_proofs::{ arithmetic::FieldExt, circuit::Region, - plonk::{Advice, Column, ConstraintSystem, Error, Expression, VirtualCells}, - poly::Rotation, + plonk::{Advice, Column, ConstraintSystem, Error}, }; use crate::evm_circuit::{table::TableColumns, witness::RwRow}; diff --git a/zkevm-circuits/src/state_circuit/lexicographic_ordering.rs b/zkevm-circuits/src/state_circuit/lexicographic_ordering.rs index dafb736ca1..13967385c0 100644 --- a/zkevm-circuits/src/state_circuit/lexicographic_ordering.rs +++ b/zkevm-circuits/src/state_circuit/lexicographic_ordering.rs @@ -6,7 +6,6 @@ use crate::{ }; use eth_types::{Field, ToBigEndian}; use gadgets::binary_number::{AsBits, BinaryNumberChip, BinaryNumberConfig}; -use halo2_proofs::arithmetic::FieldExt; use halo2_proofs::{ circuit::Region, plonk::{Advice, Column, ConstraintSystem, Error, Expression, Fixed, Instance, VirtualCells}, diff --git a/zkevm-circuits/src/super_circuit.rs b/zkevm-circuits/src/super_circuit.rs index 4fde0cb53f..0ad8d3486c 100644 --- a/zkevm-circuits/src/super_circuit.rs +++ b/zkevm-circuits/src/super_circuit.rs @@ -21,24 +21,19 @@ use crate::bytecode_circuit::bytecode_unroller::{ use crate::util::Expr; use crate::{ evm_circuit::{ - table::{BlockTable, FixedTableTag, KeccakTable, TableColumns}, - util::{rlc, RandomLinearCombination}, + table::{BlockTable, FixedTableTag, KeccakTable}, witness::Block, - EvmCircuit, {load_block, load_bytecodes, load_keccaks, load_rws, load_txs}, + EvmCircuit, {load_block, load_keccaks, load_rws}, }, rw_table::RwTable, }; -use eth_types::{Field, ToLittleEndian, Word}; -use gadgets::evm_word::encode; +use eth_types::Field; use halo2_proofs::{ arithmetic::CurveAffine, circuit::{Layouter, SimpleFloorPlanner}, - // dev::{MockProver, VerifyFailure}, - plonk::{Advice, Circuit, Column, ConstraintSystem, Error, Expression}, + plonk::{Circuit, ConstraintSystem, Error, Expression}, poly::Rotation, }; -use itertools::Itertools; -use keccak256::plain::Keccak; // The SuperCircuit contains the following circuits: // @@ -232,9 +227,7 @@ impl Circuit .iter() .map(|(_, b)| unroll(b.bytes.clone(), self.block.randomness)) .collect(); - config - .bytecode_circuit - .load(&mut layouter, &bytecodes, self.block.randomness)?; + config.bytecode_circuit.load(&mut layouter)?; config.bytecode_circuit.assign( &mut layouter, self.bytecode_size, @@ -256,7 +249,7 @@ impl Circuit load_keccaks( &config.keccak_table, &mut layouter, - &keccak_inputs, + keccak_inputs.iter().map(|b| b.as_slice()), self.block.randomness, )?; Ok(()) diff --git a/zkevm-circuits/src/tx_circuit.rs b/zkevm-circuits/src/tx_circuit.rs index e94d52bb15..a2bde9a3ca 100644 --- a/zkevm-circuits/src/tx_circuit.rs +++ b/zkevm-circuits/src/tx_circuit.rs @@ -21,7 +21,7 @@ use ff::PrimeField; use group::GroupEncoding; use halo2_proofs::{ circuit::{AssignedCell, Layouter, Region, SimpleFloorPlanner}, - plonk::{Advice, Circuit, Column, ConstraintSystem, Error, Expression, VirtualCells}, + plonk::{Advice, Circuit, Column, ConstraintSystem, Error, Expression}, poly::Rotation, }; use itertools::Itertools; @@ -523,7 +523,9 @@ impl Circuit load_keccaks( &config.keccak_table, &mut layouter, - &keccak_inputs(&self.txs, self.chain_id)?, + keccak_inputs(&self.txs, self.chain_id)? + .iter() + .map(|b| b.as_slice()), self.randomness, ) } diff --git a/zkevm-circuits/src/tx_circuit/sign_verify.rs b/zkevm-circuits/src/tx_circuit/sign_verify.rs index 108ed9b645..7d225330c5 100644 --- a/zkevm-circuits/src/tx_circuit/sign_verify.rs +++ b/zkevm-circuits/src/tx_circuit/sign_verify.rs @@ -908,9 +908,9 @@ mod sign_verify_tests { load_keccaks( &config.sign_verify.keccak_table, &mut layouter, - &keccak_inputs(&self.signatures), + keccak_inputs(&self.signatures).iter().map(|b| b.as_slice()), self.randomness, - ); + )?; Ok(()) } } From f73ac93312bc57ecd450ac6da9d4ea2e9c9daceb Mon Sep 17 00:00:00 2001 From: Eduard S Date: Mon, 18 Jul 2022 12:41:31 +0200 Subject: [PATCH 15/26] WIP --- .../src/bytecode_circuit/bytecode_unroller.rs | 28 +++--------- zkevm-circuits/src/evm_circuit.rs | 24 ++-------- zkevm-circuits/src/super_circuit.rs | 32 +++----------- zkevm-circuits/src/tx_circuit.rs | 44 +------------------ zkevm-circuits/src/tx_circuit/sign_verify.rs | 19 +------- zkevm-circuits/src/util.rs | 26 +++++++++++ 6 files changed, 44 insertions(+), 129 deletions(-) diff --git a/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs b/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs index 4d83f20cfc..8c0197a22f 100644 --- a/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs +++ b/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs @@ -3,7 +3,7 @@ use crate::{ load_keccaks, table::{BytecodeFieldTag, KeccakTable, TableColumns}, util::{ - and, constraint_builder::BaseConstraintBuilder, not, or, rlc, select, + and, constraint_builder::BaseConstraintBuilder, not, or, select, RandomLinearCombination, }, }, @@ -11,10 +11,7 @@ use crate::{ }; use bus_mapping::evm::OpcodeId; use eth_types::{Field, ToLittleEndian, Word}; -use gadgets::{ - evm_word::encode, - is_zero::{IsZeroChip, IsZeroConfig, IsZeroInstruction}, -}; +use gadgets::is_zero::{IsZeroChip, IsZeroConfig, IsZeroInstruction}; use halo2_proofs::{ circuit::{Layouter, Region}, plonk::{Advice, Column, ConstraintSystem, Error, Expression, Fixed, Selector, VirtualCells}, @@ -101,7 +98,7 @@ pub struct Config { keccak_table: KeccakTable, } -use crate::util::TableShow; +// use crate::util::TableShow; impl Config { pub(crate) fn configure( @@ -758,6 +755,7 @@ fn into_words(message: &[u8]) -> Vec { #[cfg(test)] mod tests { use super::*; + use crate::util::power_of_randomness_from_instance; use eth_types::{Bytecode, Word}; use halo2_proofs::{ circuit::{Layouter, SimpleFloorPlanner}, @@ -794,24 +792,10 @@ mod tests { value: meta.advice_column(), }; - // This gate is used just to get the array of expressions from the power of - // randomness instance column, so that later on we don't need to query - // columns everywhere, and can pass the power of randomness array - // expression everywhere. The gate itself doesn't add any constraints. - let randomness = { - let column = meta.instance_column(); - let mut randomness = None; - - meta.create_gate("", |meta| { - randomness = Some(meta.query_instance(column, Rotation::cur())); - [0.expr()] - }); - - randomness.unwrap() - }; + let randomness = power_of_randomness_from_instance::<_, 1>(meta); let keccak_table = KeccakTable::construct(meta); - Config::configure(meta, randomness, bytecode_table, keccak_table) + Config::configure(meta, randomness[0].clone(), bytecode_table, keccak_table) } fn synthesize( diff --git a/zkevm-circuits/src/evm_circuit.rs b/zkevm-circuits/src/evm_circuit.rs index 1e20c22b49..d65ec91d91 100644 --- a/zkevm-circuits/src/evm_circuit.rs +++ b/zkevm-circuits/src/evm_circuit.rs @@ -227,7 +227,7 @@ pub fn load_rws( ) } -use crate::util::TableShow; +// use crate::util::TableShow; // TODO: Move to src/tables.rs pub fn load_bytecodes<'a, F: Field>( @@ -387,14 +387,13 @@ pub mod test { use crate::{ evm_circuit::{table::FixedTableTag, witness::Block, EvmCircuit}, rw_table::RwTable, - util::Expr, + util::power_of_randomness_from_instance, }; use eth_types::{Field, Word}; use halo2_proofs::{ circuit::{Layouter, SimpleFloorPlanner}, dev::{MockProver, VerifyFailure}, plonk::{Circuit, ConstraintSystem, Error}, - poly::Rotation, }; use rand::{ distributions::uniform::{SampleRange, SampleUniform}, @@ -460,24 +459,7 @@ pub mod test { let bytecode_table = BytecodeTable::construct(meta); let block_table = BlockTable::construct(meta); - // This gate is used just to get the array of expressions from the power of - // randomness instance column, so that later on we don't need to query - // columns everywhere, and can pass the power of randomness array - // expression everywhere. The gate itself doesn't add any constraints. - let power_of_randomness = { - let columns = [(); 31].map(|_| meta.instance_column()); - let mut power_of_randomness = None; - - meta.create_gate("", |meta| { - power_of_randomness = - Some(columns.map(|column| meta.query_instance(column, Rotation::cur()))); - - [0.expr()] - }); - - power_of_randomness.unwrap() - }; - + let power_of_randomness = power_of_randomness_from_instance(meta); let evm_circuit = EvmCircuit::configure( meta, power_of_randomness, diff --git a/zkevm-circuits/src/super_circuit.rs b/zkevm-circuits/src/super_circuit.rs index 0ad8d3486c..8cfbff3b66 100644 --- a/zkevm-circuits/src/super_circuit.rs +++ b/zkevm-circuits/src/super_circuit.rs @@ -12,13 +12,13 @@ #![allow(missing_docs)] // use halo2_proofs::plonk::*; -use crate::tx_circuit::{self, sign_verify, TxCircuit, TxCircuitConfig, TxTable}; +use crate::tx_circuit::{self, TxCircuit, TxCircuitConfig, TxTable}; use crate::bytecode_circuit::bytecode_unroller::{ unroll, BytecodeTable, Config as BytecodeConfig, UnrolledBytecode, }; -use crate::util::Expr; +use crate::util::power_of_randomness_from_instance; use crate::{ evm_circuit::{ table::{BlockTable, FixedTableTag, KeccakTable}, @@ -29,10 +29,8 @@ use crate::{ }; use eth_types::Field; use halo2_proofs::{ - arithmetic::CurveAffine, circuit::{Layouter, SimpleFloorPlanner}, plonk::{Circuit, ConstraintSystem, Error, Expression}, - poly::Rotation, }; // The SuperCircuit contains the following circuits: @@ -128,23 +126,7 @@ impl Circuit let block_table = BlockTable::construct(meta); let keccak_table = KeccakTable::construct(meta); - // This gate is used just to get the array of expressions from the power of - // randomness instance column, so that later on we don't need to query - // columns everywhere, and can pass the power of randomness array - // expression everywhere. The gate itself doesn't add any constraints. - let power_of_randomness = { - let columns = [(); sign_verify::POW_RAND_SIZE].map(|_| meta.instance_column()); - let mut power_of_randomness = None; - - meta.create_gate("", |meta| { - power_of_randomness = - Some(columns.map(|column| meta.query_instance(column, Rotation::cur()))); - - [0.expr()] - }); - - power_of_randomness.unwrap() - }; + let power_of_randomness = power_of_randomness_from_instance(meta); let evm_circuit = EvmCircuit::configure( meta, power_of_randomness[..31] @@ -292,11 +274,7 @@ pub mod test { mod super_circuit_tests { use super::test::*; use super::*; - use crate::{ - evm_circuit::witness::block_convert, - // test_util::{run_test_circuits, BytecodeTestConfig}, - tx_circuit::sign_verify::POW_RAND_SIZE, - }; + use crate::{evm_circuit::witness::block_convert, tx_circuit::sign_verify::POW_RAND_SIZE}; use bus_mapping::mock::BlockData; use eth_types::{ address, bytecode, @@ -305,7 +283,7 @@ mod super_circuit_tests { }; use ethers_signers::{LocalWallet, Signer}; use group::{Curve, Group}; - use halo2_proofs::arithmetic::Field as Halo2Field; + use halo2_proofs::arithmetic::{CurveAffine, Field as Halo2Field}; use halo2_proofs::dev::{MockProver, VerifyConfig, VerifyFailure}; use halo2_proofs::pairing::bn256::Fr; use mock::{TestContext, MOCK_CHAIN_ID}; diff --git a/zkevm-circuits/src/tx_circuit.rs b/zkevm-circuits/src/tx_circuit.rs index a2bde9a3ca..ef17f6e1ee 100644 --- a/zkevm-circuits/src/tx_circuit.rs +++ b/zkevm-circuits/src/tx_circuit.rs @@ -13,7 +13,7 @@ use crate::evm_circuit::{ table::{KeccakTable, TableColumns}, }; use crate::impl_expr; -use crate::util::{random_linear_combine_word as rlc, Expr}; +use crate::util::{power_of_randomness_from_instance, random_linear_combine_word as rlc}; use eth_types::{ geth_types::Transaction, Address, Field, ToBigEndian, ToLittleEndian, ToScalar, Word, }; @@ -22,7 +22,6 @@ use group::GroupEncoding; use halo2_proofs::{ circuit::{AssignedCell, Layouter, Region, SimpleFloorPlanner}, plonk::{Advice, Circuit, Column, ConstraintSystem, Error, Expression}, - poly::Rotation, }; use itertools::Itertools; use lazy_static::lazy_static; @@ -236,34 +235,12 @@ impl TxCircuitConfig { tx_table: TxTable, keccak_table: KeccakTable, ) -> Self { - // let tx_id = meta.advice_column(); - // let tag = meta.advice_column(); - // let index = meta.advice_column(); - // let value = meta.advice_column(); let tx_id = tx_table.tx_id; let tag = tx_table.tag; let index = tx_table.index; let value = tx_table.value; meta.enable_equality(value); - // This gate is used just to get the array of expressions from the power of - // randomness instance column, so that later on we don't need to query - // columns everywhere, and can pass the power of randomness array - // expression everywhere. The gate itself doesn't add any constraints. - // let power_of_randomness = { - // let columns = [(); sign_verify::POW_RAND_SIZE].map(|_| - // meta.instance_column()); let mut power_of_randomness = None; - - // meta.create_gate("power of randomness", |meta| { - // power_of_randomness = - // Some(columns.map(|column| meta.query_instance(column, - // Rotation::cur()))); - - // [0.expr()] - // }); - - // power_of_randomness.unwrap() - // }; let sign_verify = SignVerifyConfig::new(meta, power_of_randomness, keccak_table.clone()); Self { @@ -492,24 +469,7 @@ impl Circuit value: meta.advice_column(), }; - // This gate is used just to get the array of expressions from the power of - // randomness instance column, so that later on we don't need to query - // columns everywhere, and can pass the power of randomness array - // expression everywhere. The gate itself doesn't add any constraints. - let power_of_randomness = { - let columns = [(); sign_verify::POW_RAND_SIZE].map(|_| meta.instance_column()); - let mut power_of_randomness = None; - - meta.create_gate("", |meta| { - power_of_randomness = - Some(columns.map(|column| meta.query_instance(column, Rotation::cur()))); - - [0.expr()] - }); - - power_of_randomness.unwrap() - }; - + let power_of_randomness = power_of_randomness_from_instance(meta); let keccak_table = KeccakTable::construct(meta); TxCircuitConfig::new(meta, power_of_randomness, tx_table, keccak_table) } diff --git a/zkevm-circuits/src/tx_circuit/sign_verify.rs b/zkevm-circuits/src/tx_circuit/sign_verify.rs index 7d225330c5..74caf84459 100644 --- a/zkevm-circuits/src/tx_circuit/sign_verify.rs +++ b/zkevm-circuits/src/tx_circuit/sign_verify.rs @@ -836,6 +836,7 @@ fn pub_key_hash_to_address(pk_hash: &[u8]) -> F { #[cfg(test)] mod sign_verify_tests { use super::*; + use crate::util::power_of_randomness_from_instance; use group::Group; use halo2_proofs::{ circuit::SimpleFloorPlanner, dev::MockProver, pairing::bn256::Fr, plonk::Circuit, @@ -851,23 +852,7 @@ mod sign_verify_tests { impl TestCircuitSignVerifyConfig { pub(crate) fn new(meta: &mut ConstraintSystem) -> Self { - // This gate is used just to get the array of expressions from the power of - // randomness instance column, so that later on we don't need to query - // columns everywhere, and can pass the power of randomness array - // expression everywhere. The gate itself doesn't add any constraints. - let power_of_randomness = { - let columns = [(); POW_RAND_SIZE].map(|_| meta.instance_column()); - let mut power_of_randomness = None; - - meta.create_gate("power of randomness", |meta| { - power_of_randomness = - Some(columns.map(|column| meta.query_instance(column, Rotation::cur()))); - - [0.expr()] - }); - - power_of_randomness.unwrap() - }; + let power_of_randomness = power_of_randomness_from_instance(meta); let keccak_table = KeccakTable::construct(meta); let sign_verify = SignVerifyConfig::new(meta, power_of_randomness, keccak_table); diff --git a/zkevm-circuits/src/util.rs b/zkevm-circuits/src/util.rs index 4eccc50894..443fdeb55b 100644 --- a/zkevm-circuits/src/util.rs +++ b/zkevm-circuits/src/util.rs @@ -1,5 +1,9 @@ //! Common utility traits and functions. use eth_types::Field; +use halo2_proofs::{ + plonk::{ConstraintSystem, Expression}, + poly::Rotation, +}; pub use gadgets::util::Expr; @@ -71,3 +75,25 @@ impl TableShow { } } } + +/// TODO +pub fn power_of_randomness_from_instance( + meta: &mut ConstraintSystem, +) -> [Expression; N] { + // This gate is used just to get the array of expressions from the power of + // randomness instance column, so that later on we don't need to query + // columns everywhere, and can pass the power of randomness array + // expression everywhere. The gate itself doesn't add any constraints. + + let columns = [(); N].map(|_| meta.instance_column()); + let mut power_of_randomness = None; + + meta.create_gate("power of randomness from instance", |meta| { + power_of_randomness = + Some(columns.map(|column| meta.query_instance(column, Rotation::cur()))); + + [0.expr()] + }); + + power_of_randomness.unwrap() +} From 0c295cdbd9fd5a650e42abd67ac23ea8444d2a15 Mon Sep 17 00:00:00 2001 From: Eduard S Date: Mon, 18 Jul 2022 16:30:33 +0200 Subject: [PATCH 16/26] Move cross-circuit table stuff to src/table.rs --- .../src/bytecode_circuit/bytecode_unroller.rs | 46 +- zkevm-circuits/src/evm_circuit.rs | 249 +------- .../src/evm_circuit/execution/begin_tx.rs | 2 +- .../src/evm_circuit/execution/block_ctx.rs | 2 +- .../src/evm_circuit/execution/call.rs | 2 +- .../src/evm_circuit/execution/calldatacopy.rs | 2 +- .../src/evm_circuit/execution/calldataload.rs | 2 +- .../src/evm_circuit/execution/calldatasize.rs | 2 +- .../src/evm_circuit/execution/caller.rs | 2 +- .../src/evm_circuit/execution/callvalue.rs | 2 +- .../src/evm_circuit/execution/chainid.rs | 2 +- .../execution/copy_code_to_memory.rs | 8 +- .../src/evm_circuit/execution/copy_to_log.rs | 9 +- .../src/evm_circuit/execution/end_tx.rs | 8 +- .../src/evm_circuit/execution/extcodehash.rs | 2 +- .../src/evm_circuit/execution/gasprice.rs | 2 +- .../src/evm_circuit/execution/logs.rs | 2 +- .../src/evm_circuit/execution/memory_copy.rs | 9 +- .../src/evm_circuit/execution/origin.rs | 2 +- .../src/evm_circuit/execution/selfbalance.rs | 2 +- .../src/evm_circuit/execution/sload.rs | 2 +- .../src/evm_circuit/execution/sstore.rs | 2 +- .../src/evm_circuit/execution/stop.rs | 2 +- zkevm-circuits/src/evm_circuit/table.rs | 185 +----- .../src/evm_circuit/util/common_gadget.rs | 3 +- .../evm_circuit/util/constraint_builder.rs | 8 +- zkevm-circuits/src/evm_circuit/witness.rs | 5 +- zkevm-circuits/src/lib.rs | 1 + zkevm-circuits/src/rw_table.rs | 82 --- zkevm-circuits/src/state_circuit.rs | 5 +- .../src/state_circuit/constraint_builder.rs | 5 +- zkevm-circuits/src/state_circuit/lookups.rs | 2 +- zkevm-circuits/src/state_circuit/test.rs | 5 +- zkevm-circuits/src/super_circuit.rs | 16 +- zkevm-circuits/src/table.rs | 594 ++++++++++++++++++ zkevm-circuits/src/tx_circuit.rs | 67 +- zkevm-circuits/src/tx_circuit/sign_verify.rs | 3 +- 37 files changed, 673 insertions(+), 671 deletions(-) create mode 100644 zkevm-circuits/src/table.rs diff --git a/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs b/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs index 8c0197a22f..fe9f1dab34 100644 --- a/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs +++ b/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs @@ -1,12 +1,9 @@ use crate::{ - evm_circuit::{ - load_keccaks, - table::{BytecodeFieldTag, KeccakTable, TableColumns}, - util::{ - and, constraint_builder::BaseConstraintBuilder, not, or, select, - RandomLinearCombination, - }, + evm_circuit::util::{ + and, constraint_builder::BaseConstraintBuilder, not, or, select, RandomLinearCombination, }, + table::{load_keccaks, BytecodeTable, KeccakTable}, + table::{BytecodeFieldTag, TableColumns}, util::Expr, }; use bus_mapping::evm::OpcodeId; @@ -41,41 +38,6 @@ pub struct UnrolledBytecode { rows: Vec>, } -// CHANGELOG: Added BytecodeTable to help reusing the table config with other -// circuits -#[derive(Clone, Debug)] -pub struct BytecodeTable { - pub code_hash: Column, // CHANGELOG: Renamed from hash - pub tag: Column, - pub index: Column, - pub is_code: Column, - pub value: Column, -} - -impl BytecodeTable { - pub fn construct(meta: &mut ConstraintSystem) -> Self { - Self { - code_hash: meta.advice_column(), - tag: meta.advice_column(), - index: meta.advice_column(), - is_code: meta.advice_column(), - value: meta.advice_column(), - } - } -} - -impl TableColumns for BytecodeTable { - fn columns(&self) -> Vec> { - vec![ - self.code_hash, - self.tag, - self.index, - self.is_code, - self.value, - ] - } -} - #[derive(Clone, Debug)] pub struct Config { randomness: Expression, diff --git a/zkevm-circuits/src/evm_circuit.rs b/zkevm-circuits/src/evm_circuit.rs index d65ec91d91..d622f75fc2 100644 --- a/zkevm-circuits/src/evm_circuit.rs +++ b/zkevm-circuits/src/evm_circuit.rs @@ -11,20 +11,11 @@ pub(crate) mod util; pub mod table; pub mod witness; -use crate::bytecode_circuit::bytecode_unroller::BytecodeTable; -use crate::tx_circuit::TxTable; -use crate::{ - evm_circuit::{ - util::{rlc, RandomLinearCombination}, - witness::{BlockContext, Bytecode, RwMap, Transaction}, - }, - rw_table::RwTable, -}; -use eth_types::{Field, ToLittleEndian, Word}; +use crate::table::{BytecodeTable, TxTable}; +use eth_types::Field; use execution::ExecutionConfig; use itertools::Itertools; -use keccak256::plain::Keccak; -use table::{BlockTable, FixedTableTag, KeccakTable, LookupTable, TableColumns}; +use table::{FixedTableTag, LookupTable}; use witness::Block; /// EvmCircuit implements verification of execution trace of a block. @@ -149,244 +140,12 @@ impl EvmCircuit { } } -// TODO: Move to src/tables.rs -pub fn load_txs( - tx_table: &TxTable, - layouter: &mut impl Layouter, - txs: &[Transaction], - randomness: F, -) -> Result<(), Error> { - layouter.assign_region( - || "tx table", - |mut region| { - let mut offset = 0; - for column in tx_table.columns() { - region.assign_advice( - || "tx table all-zero row", - column, - offset, - || Ok(F::zero()), - )?; - } - offset += 1; - - // println!("DBG load_txs"); - let tx_table_columns = tx_table.columns(); - for tx in txs.iter() { - for row in tx.table_assignments(randomness) { - // print!("{:02} ", offset); - for (column, value) in tx_table_columns.iter().zip_eq(row) { - // print!("{:?} ", value); - region.assign_advice( - || format!("tx table row {}", offset), - *column, - offset, - || Ok(value), - )?; - } - offset += 1; - // println!(""); - } - } - Ok(()) - }, - ) -} - -// TODO: Move to src/tables.rs -pub fn load_rws( - rw_table: &RwTable, - layouter: &mut impl Layouter, - rws: &RwMap, - randomness: F, -) -> Result<(), Error> { - layouter.assign_region( - || "rw table", - |mut region| { - let mut offset = 0; - rw_table.assign(&mut region, offset, &Default::default())?; - offset += 1; - - let mut rows = rws - .0 - .values() - .flat_map(|rws| rws.iter()) - .collect::>(); - - rows.sort_by_key(|a| a.rw_counter()); - let mut expected_rw_counter = 1; - for rw in rows { - assert!(rw.rw_counter() == expected_rw_counter); - expected_rw_counter += 1; - - rw_table.assign(&mut region, offset, &rw.table_assignment(randomness))?; - offset += 1; - } - Ok(()) - }, - ) -} - -// use crate::util::TableShow; - -// TODO: Move to src/tables.rs -pub fn load_bytecodes<'a, F: Field>( - bytecode_table: &BytecodeTable, - layouter: &mut impl Layouter, - bytecodes: impl IntoIterator + Clone, - randomness: F, -) -> Result<(), Error> { - // println!("> load_bytecodes"); - // let mut table = TableShow::::new(vec!["codeHash", "tag", "index", - // "isCode", "value"]); - layouter.assign_region( - || "bytecode table", - |mut region| { - let mut offset = 0; - for column in bytecode_table.columns() { - region.assign_advice( - || "bytecode table all-zero row", - column, - offset, - || Ok(F::zero()), - )?; - } - offset += 1; - - let bytecode_table_columns = bytecode_table.columns(); - for bytecode in bytecodes.clone() { - for row in bytecode.table_assignments(randomness) { - // let mut column_index = 0; - for (column, value) in bytecode_table_columns.iter().zip_eq(row) { - region.assign_advice( - || format!("bytecode table row {}", offset), - *column, - offset, - || Ok(value), - )?; - // table.push(column_index, value); - // column_index += 1; - } - offset += 1; - } - } - // table.print(); - Ok(()) - }, - ) -} - -// TODO: Move to src/tables.rs -pub fn load_block( - block_table: &BlockTable, - layouter: &mut impl Layouter, - block: &BlockContext, - randomness: F, -) -> Result<(), Error> { - layouter.assign_region( - || "block table", - |mut region| { - let mut offset = 0; - for column in block_table.columns() { - region.assign_advice( - || "block table all-zero row", - column, - offset, - || Ok(F::zero()), - )?; - } - offset += 1; - - let block_table_columns = block_table.columns(); - for row in block.table_assignments(randomness) { - for (column, value) in block_table_columns.iter().zip_eq(row) { - region.assign_advice( - || format!("block table row {}", offset), - *column, - offset, - || Ok(value), - )?; - } - offset += 1; - } - - Ok(()) - }, - ) -} - -pub fn keccak_table_assignments(input: &[u8], randomness: F) -> Vec<[F; 4]> { - // CHANGELOG: Using `RLC(reversed(input))` - let input_rlc: F = rlc::value(input.iter().rev(), randomness); - let input_len = F::from(input.len() as u64); - let mut keccak = Keccak::default(); - keccak.update(input); - let output = keccak.digest(); - let output_rlc = RandomLinearCombination::::random_linear_combine( - Word::from_big_endian(output.as_slice()).to_le_bytes(), - randomness, - ); - - vec![[F::one(), input_rlc, input_len, output_rlc]] -} - -// NOTE: For now, the input_rlc of the keccak is defined as -// `RLC(reversed(input))` for convenience of the circuits that do the lookups. -// This allows calculating the `input_rlc` after all the inputs bytes have been -// layed out via the pattern `acc[i] = acc[i-1] * r + value[i]`. -pub fn load_keccaks<'a, F: Field>( - keccak_table: &KeccakTable, - layouter: &mut impl Layouter, - inputs: impl IntoIterator + Clone, - randomness: F, -) -> Result<(), Error> { - // println!("> super_circuit.load_keccaks"); - // let mut table = TableShow::::new(vec!["is_enabled", "input_rlc", - // "input_len", "output_rlc"]); - layouter.assign_region( - || "keccak table", - |mut region| { - let mut offset = 0; - for column in keccak_table.columns() { - region.assign_advice( - || "keccak table all-zero row", - column, - offset, - || Ok(F::zero()), - )?; - } - offset += 1; - - let keccak_table_columns = keccak_table.columns(); - for input in inputs.clone() { - // println!("+ {:?}", input); - for row in keccak_table_assignments(input, randomness) { - // let mut column_index = 0; - for (column, value) in keccak_table_columns.iter().zip_eq(row) { - region.assign_advice( - || format!("keccak table row {}", offset), - *column, - offset, - || Ok(value), - )?; - // table.push(column_index, value); - // column_index += 1; - } - offset += 1; - } - } - // table.print(); - Ok(()) - }, - ) -} - #[cfg(any(feature = "test", test))] pub mod test { use super::*; use crate::{ evm_circuit::{table::FixedTableTag, witness::Block, EvmCircuit}, - rw_table::RwTable, + table::{load_block, load_bytecodes, load_rws, load_txs, BlockTable, RwTable}, util::power_of_randomness_from_instance, }; use eth_types::{Field, Word}; diff --git a/zkevm-circuits/src/evm_circuit/execution/begin_tx.rs b/zkevm-circuits/src/evm_circuit/execution/begin_tx.rs index 7a3c655c41..51d2b9df8a 100644 --- a/zkevm-circuits/src/evm_circuit/execution/begin_tx.rs +++ b/zkevm-circuits/src/evm_circuit/execution/begin_tx.rs @@ -3,7 +3,6 @@ use crate::{ execution::ExecutionGadget, param::N_BYTES_GAS, step::ExecutionState, - table::{AccountFieldTag, CallContextFieldTag, TxContextFieldTag}, util::{ common_gadget::TransferWithGasFeeGadget, constraint_builder::{ @@ -15,6 +14,7 @@ use crate::{ }, witness::{Block, Call, ExecStep, Transaction}, }, + table::{AccountFieldTag, CallContextFieldTag, TxFieldTag as TxContextFieldTag}, util::Expr, }; use eth_types::{evm_types::GasCost, Field, ToLittleEndian, ToScalar}; diff --git a/zkevm-circuits/src/evm_circuit/execution/block_ctx.rs b/zkevm-circuits/src/evm_circuit/execution/block_ctx.rs index 56115f070c..8be3c2a657 100644 --- a/zkevm-circuits/src/evm_circuit/execution/block_ctx.rs +++ b/zkevm-circuits/src/evm_circuit/execution/block_ctx.rs @@ -3,7 +3,6 @@ use crate::{ execution::ExecutionGadget, param::{N_BYTES_ACCOUNT_ADDRESS, N_BYTES_U64, N_BYTES_WORD}, step::ExecutionState, - table::BlockContextFieldTag, util::{ common_gadget::SameContextGadget, constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, @@ -11,6 +10,7 @@ use crate::{ }, witness::{Block, Call, ExecStep, Transaction}, }, + table::BlockContextFieldTag, util::Expr, }; use bus_mapping::evm::OpcodeId; diff --git a/zkevm-circuits/src/evm_circuit/execution/call.rs b/zkevm-circuits/src/evm_circuit/execution/call.rs index 435575739d..e0fc80c949 100644 --- a/zkevm-circuits/src/evm_circuit/execution/call.rs +++ b/zkevm-circuits/src/evm_circuit/execution/call.rs @@ -3,7 +3,6 @@ use crate::{ execution::ExecutionGadget, param::{N_BYTES_ACCOUNT_ADDRESS, N_BYTES_GAS, N_BYTES_MEMORY_WORD_SIZE}, step::ExecutionState, - table::{AccountFieldTag, CallContextFieldTag}, util::{ common_gadget::TransferGadget, constraint_builder::{ @@ -20,6 +19,7 @@ use crate::{ }, witness::{Block, Call, ExecStep, Transaction}, }, + table::{AccountFieldTag, CallContextFieldTag}, util::Expr, }; use bus_mapping::evm::OpcodeId; diff --git a/zkevm-circuits/src/evm_circuit/execution/calldatacopy.rs b/zkevm-circuits/src/evm_circuit/execution/calldatacopy.rs index 327279607d..cdbcc5de67 100644 --- a/zkevm-circuits/src/evm_circuit/execution/calldatacopy.rs +++ b/zkevm-circuits/src/evm_circuit/execution/calldatacopy.rs @@ -3,7 +3,6 @@ use crate::{ execution::ExecutionGadget, param::{N_BYTES_MEMORY_ADDRESS, N_BYTES_MEMORY_WORD_SIZE}, step::ExecutionState, - table::CallContextFieldTag, util::{ common_gadget::SameContextGadget, constraint_builder::{ @@ -16,6 +15,7 @@ use crate::{ }, witness::{Block, Call, ExecStep, Transaction}, }, + table::CallContextFieldTag, util::Expr, }; use bus_mapping::evm::OpcodeId; diff --git a/zkevm-circuits/src/evm_circuit/execution/calldataload.rs b/zkevm-circuits/src/evm_circuit/execution/calldataload.rs index a4742b4d67..eacf96a3ba 100644 --- a/zkevm-circuits/src/evm_circuit/execution/calldataload.rs +++ b/zkevm-circuits/src/evm_circuit/execution/calldataload.rs @@ -5,10 +5,10 @@ use eth_types::{Field, ToLittleEndian}; use halo2_proofs::plonk::{Error, Expression}; use crate::{ + table::{CallContextFieldTag, TxContextFieldTag}, evm_circuit::{ param::{N_BYTES_MEMORY_ADDRESS, N_BYTES_WORD}, step::ExecutionState, - table::{CallContextFieldTag, TxContextFieldTag}, util::{ common_gadget::SameContextGadget, constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, diff --git a/zkevm-circuits/src/evm_circuit/execution/calldatasize.rs b/zkevm-circuits/src/evm_circuit/execution/calldatasize.rs index c8ef0af926..a80f2d001b 100644 --- a/zkevm-circuits/src/evm_circuit/execution/calldatasize.rs +++ b/zkevm-circuits/src/evm_circuit/execution/calldatasize.rs @@ -1,9 +1,9 @@ use crate::{ + table::CallContextFieldTag, evm_circuit::{ execution::ExecutionGadget, param::N_BYTES_CALLDATASIZE, step::ExecutionState, - table::CallContextFieldTag, util::{ common_gadget::SameContextGadget, constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, diff --git a/zkevm-circuits/src/evm_circuit/execution/caller.rs b/zkevm-circuits/src/evm_circuit/execution/caller.rs index 2bb0e22fa7..1a67356bd8 100644 --- a/zkevm-circuits/src/evm_circuit/execution/caller.rs +++ b/zkevm-circuits/src/evm_circuit/execution/caller.rs @@ -1,9 +1,9 @@ use crate::{ + table::CallContextFieldTag, evm_circuit::{ execution::ExecutionGadget, param::N_BYTES_ACCOUNT_ADDRESS, step::ExecutionState, - table::CallContextFieldTag, util::{ common_gadget::SameContextGadget, constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, diff --git a/zkevm-circuits/src/evm_circuit/execution/callvalue.rs b/zkevm-circuits/src/evm_circuit/execution/callvalue.rs index 989a158d09..1ed909d33a 100644 --- a/zkevm-circuits/src/evm_circuit/execution/callvalue.rs +++ b/zkevm-circuits/src/evm_circuit/execution/callvalue.rs @@ -1,8 +1,8 @@ use crate::{ + table::CallContextFieldTag, evm_circuit::{ execution::ExecutionGadget, step::ExecutionState, - table::CallContextFieldTag, util::{ common_gadget::SameContextGadget, constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, diff --git a/zkevm-circuits/src/evm_circuit/execution/chainid.rs b/zkevm-circuits/src/evm_circuit/execution/chainid.rs index 184fb4c843..1d4ed3f2b3 100644 --- a/zkevm-circuits/src/evm_circuit/execution/chainid.rs +++ b/zkevm-circuits/src/evm_circuit/execution/chainid.rs @@ -1,8 +1,8 @@ use crate::{ + table::BlockContextFieldTag, evm_circuit::{ execution::ExecutionGadget, step::ExecutionState, - table::BlockContextFieldTag, util::{ common_gadget::SameContextGadget, constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, diff --git a/zkevm-circuits/src/evm_circuit/execution/copy_code_to_memory.rs b/zkevm-circuits/src/evm_circuit/execution/copy_code_to_memory.rs index 488b201133..9765562518 100644 --- a/zkevm-circuits/src/evm_circuit/execution/copy_code_to_memory.rs +++ b/zkevm-circuits/src/evm_circuit/execution/copy_code_to_memory.rs @@ -260,12 +260,14 @@ pub(crate) mod test { use halo2_proofs::arithmetic::BaseExt; use halo2_proofs::pairing::bn256::Fr; - use crate::evm_circuit::{ + use crate::{ + evm_circuit::{ step::ExecutionState, - table::RwTableTag, test::run_test_circuit_incomplete_fixed_table, witness::{Block, Bytecode, Call, ExecStep, Rw, RwMap, Transaction}, - }; + }, + table::RwTableTag, +}; #[allow(clippy::too_many_arguments)] pub(crate) fn make_copy_code_step( diff --git a/zkevm-circuits/src/evm_circuit/execution/copy_to_log.rs b/zkevm-circuits/src/evm_circuit/execution/copy_to_log.rs index d90bba5b9d..aafba441d5 100644 --- a/zkevm-circuits/src/evm_circuit/execution/copy_to_log.rs +++ b/zkevm-circuits/src/evm_circuit/execution/copy_to_log.rs @@ -3,7 +3,6 @@ use crate::{ execution::ExecutionGadget, param::{N_BYTES_MEMORY_ADDRESS, N_BYTES_MEMORY_WORD_SIZE}, step::ExecutionState, - table::TxLogFieldTag, util::{ constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, math_gadget::ComparisonGadget, @@ -12,6 +11,7 @@ use crate::{ }, witness::{Block, Call, ExecStep, Transaction}, }, + table::TxLogFieldTag, util::Expr, }; use bus_mapping::{circuit_input_builder::CopyDetails, constants::MAX_COPY_BYTES}; @@ -229,12 +229,13 @@ impl ExecutionGadget for CopyToLogGadget { #[cfg(test)] pub mod test { - use crate::evm_circuit::{ + use crate::{evm_circuit::{ step::ExecutionState, - table::{RwTableTag, TxLogFieldTag}, test::{rand_bytes, run_test_circuit_incomplete_fixed_table}, witness::{Block, Bytecode, Call, ExecStep, Rw, RwMap, Transaction}, - }; + }, + table::{RwTableTag, TxLogFieldTag}, +}; use bus_mapping::{ circuit_input_builder::{CopyDetails, StepAuxiliaryData}, constants::MAX_COPY_BYTES, diff --git a/zkevm-circuits/src/evm_circuit/execution/end_tx.rs b/zkevm-circuits/src/evm_circuit/execution/end_tx.rs index 3a37717e7c..df9a0fd0f7 100644 --- a/zkevm-circuits/src/evm_circuit/execution/end_tx.rs +++ b/zkevm-circuits/src/evm_circuit/execution/end_tx.rs @@ -1,12 +1,12 @@ use crate::{ - evm_circuit::{ - execution::ExecutionGadget, - param::N_BYTES_GAS, - step::ExecutionState, table::{ BlockContextFieldTag, CallContextFieldTag, RwTableTag, TxContextFieldTag, TxReceiptFieldTag, }, + evm_circuit::{ + execution::ExecutionGadget, + param::N_BYTES_GAS, + step::ExecutionState, util::{ common_gadget::UpdateBalanceGadget, constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, diff --git a/zkevm-circuits/src/evm_circuit/execution/extcodehash.rs b/zkevm-circuits/src/evm_circuit/execution/extcodehash.rs index 64a712e749..51cb42cf1c 100644 --- a/zkevm-circuits/src/evm_circuit/execution/extcodehash.rs +++ b/zkevm-circuits/src/evm_circuit/execution/extcodehash.rs @@ -1,9 +1,9 @@ use crate::{ + table::{AccountFieldTag, CallContextFieldTag}, evm_circuit::{ execution::ExecutionGadget, param::N_BYTES_ACCOUNT_ADDRESS, step::ExecutionState, - table::{AccountFieldTag, CallContextFieldTag}, util::{ common_gadget::SameContextGadget, constraint_builder::{ diff --git a/zkevm-circuits/src/evm_circuit/execution/gasprice.rs b/zkevm-circuits/src/evm_circuit/execution/gasprice.rs index ef132b5a6d..0dcfb6dd0f 100644 --- a/zkevm-circuits/src/evm_circuit/execution/gasprice.rs +++ b/zkevm-circuits/src/evm_circuit/execution/gasprice.rs @@ -1,8 +1,8 @@ use crate::{ + table::{CallContextFieldTag, TxContextFieldTag}, evm_circuit::{ execution::ExecutionGadget, step::ExecutionState, - table::{CallContextFieldTag, TxContextFieldTag}, util::{ common_gadget::SameContextGadget, constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, diff --git a/zkevm-circuits/src/evm_circuit/execution/logs.rs b/zkevm-circuits/src/evm_circuit/execution/logs.rs index 1fbcbefe93..13690fc158 100644 --- a/zkevm-circuits/src/evm_circuit/execution/logs.rs +++ b/zkevm-circuits/src/evm_circuit/execution/logs.rs @@ -1,9 +1,9 @@ use crate::{ + table::{CallContextFieldTag, RwTableTag, TxLogFieldTag}, evm_circuit::{ execution::ExecutionGadget, param::N_BYTES_MEMORY_WORD_SIZE, step::ExecutionState, - table::{CallContextFieldTag, RwTableTag, TxLogFieldTag}, util::{ common_gadget::SameContextGadget, constraint_builder::{ diff --git a/zkevm-circuits/src/evm_circuit/execution/memory_copy.rs b/zkevm-circuits/src/evm_circuit/execution/memory_copy.rs index 21b071b48a..c1d57c58f0 100644 --- a/zkevm-circuits/src/evm_circuit/execution/memory_copy.rs +++ b/zkevm-circuits/src/evm_circuit/execution/memory_copy.rs @@ -1,9 +1,9 @@ use crate::{ + table::TxContextFieldTag, evm_circuit::{ execution::ExecutionGadget, param::{N_BYTES_MEMORY_ADDRESS, N_BYTES_MEMORY_WORD_SIZE}, step::ExecutionState, - table::TxContextFieldTag, util::{ constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, math_gadget::ComparisonGadget, @@ -235,13 +235,14 @@ impl ExecutionGadget for CopyToMemoryGadget { #[cfg(test)] pub mod test { - use crate::evm_circuit::{ + use crate::{evm_circuit::{ execution::memory_copy::MAX_COPY_BYTES, step::ExecutionState, - table::RwTableTag, test::{rand_bytes, run_test_circuit_incomplete_fixed_table}, witness::{Block, Bytecode, Call, ExecStep, Rw, RwMap, Transaction}, - }; + }, + table::RwTableTag, +}; use bus_mapping::circuit_input_builder::{CopyDetails, StepAuxiliaryData}; use eth_types::evm_types::OpcodeId; use halo2_proofs::arithmetic::BaseExt; diff --git a/zkevm-circuits/src/evm_circuit/execution/origin.rs b/zkevm-circuits/src/evm_circuit/execution/origin.rs index 1c97fc3c16..988ab43e42 100644 --- a/zkevm-circuits/src/evm_circuit/execution/origin.rs +++ b/zkevm-circuits/src/evm_circuit/execution/origin.rs @@ -1,9 +1,9 @@ use crate::{ + table::{CallContextFieldTag, TxContextFieldTag}, evm_circuit::{ execution::ExecutionGadget, param::N_BYTES_ACCOUNT_ADDRESS, step::ExecutionState, - table::{CallContextFieldTag, TxContextFieldTag}, util::{ common_gadget::SameContextGadget, constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, diff --git a/zkevm-circuits/src/evm_circuit/execution/selfbalance.rs b/zkevm-circuits/src/evm_circuit/execution/selfbalance.rs index 42805a46f2..91b751efe4 100644 --- a/zkevm-circuits/src/evm_circuit/execution/selfbalance.rs +++ b/zkevm-circuits/src/evm_circuit/execution/selfbalance.rs @@ -1,8 +1,8 @@ use crate::{ + table::{AccountFieldTag, CallContextFieldTag}, evm_circuit::{ execution::ExecutionGadget, step::ExecutionState, - table::{AccountFieldTag, CallContextFieldTag}, util::{ common_gadget::SameContextGadget, constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, diff --git a/zkevm-circuits/src/evm_circuit/execution/sload.rs b/zkevm-circuits/src/evm_circuit/execution/sload.rs index b39b998946..22230c919d 100644 --- a/zkevm-circuits/src/evm_circuit/execution/sload.rs +++ b/zkevm-circuits/src/evm_circuit/execution/sload.rs @@ -1,8 +1,8 @@ use crate::{ + table::CallContextFieldTag, evm_circuit::{ execution::ExecutionGadget, step::ExecutionState, - table::CallContextFieldTag, util::{ common_gadget::SameContextGadget, constraint_builder::{ diff --git a/zkevm-circuits/src/evm_circuit/execution/sstore.rs b/zkevm-circuits/src/evm_circuit/execution/sstore.rs index 599e90c871..0970e84bf4 100644 --- a/zkevm-circuits/src/evm_circuit/execution/sstore.rs +++ b/zkevm-circuits/src/evm_circuit/execution/sstore.rs @@ -1,8 +1,8 @@ use crate::{ + table::CallContextFieldTag, evm_circuit::{ execution::ExecutionGadget, step::ExecutionState, - table::CallContextFieldTag, util::{ common_gadget::SameContextGadget, constraint_builder::{ diff --git a/zkevm-circuits/src/evm_circuit/execution/stop.rs b/zkevm-circuits/src/evm_circuit/execution/stop.rs index a76cd3c28a..d19de77624 100644 --- a/zkevm-circuits/src/evm_circuit/execution/stop.rs +++ b/zkevm-circuits/src/evm_circuit/execution/stop.rs @@ -1,8 +1,8 @@ use crate::{ + table::CallContextFieldTag, evm_circuit::{ execution::ExecutionGadget, step::ExecutionState, - table::CallContextFieldTag, util::{ common_gadget::RestoreContextGadget, constraint_builder::{ diff --git a/zkevm-circuits/src/evm_circuit/table.rs b/zkevm-circuits/src/evm_circuit/table.rs index f61ed74c77..a8f28f0aa6 100644 --- a/zkevm-circuits/src/evm_circuit/table.rs +++ b/zkevm-circuits/src/evm_circuit/table.rs @@ -1,17 +1,14 @@ use crate::evm_circuit::step::ExecutionState; use crate::impl_expr; -pub use crate::tx_circuit::TxFieldTag as TxContextFieldTag; +use crate::table::TableColumns; +pub use crate::table::TxContextFieldTag; use eth_types::Field; use halo2_proofs::{ - plonk::{Advice, Column, ColumnType, ConstraintSystem, Expression, Fixed, VirtualCells}, + plonk::{Advice, Column, Expression, Fixed, VirtualCells}, poly::Rotation, }; use strum::IntoEnumIterator; -use strum_macros::{EnumCount, EnumIter}; - -pub trait TableColumns { - fn columns(&self) -> Vec>; -} +use strum_macros::EnumIter; pub trait LookupTable { fn table_exprs(&self, meta: &mut VirtualCells) -> Vec>; @@ -51,6 +48,7 @@ pub enum FixedTableTag { ResponsibleOpcode, Pow2, } +impl_expr!(FixedTableTag); impl FixedTableTag { pub fn build(&self) -> Box> { @@ -136,124 +134,6 @@ impl FixedTableTag { // CallData, // } -// Keep the sequence consistent with OpcodeId for scalar -#[derive(Clone, Copy, Debug)] -pub enum BlockContextFieldTag { - Coinbase = 1, - Timestamp, - Number, - Difficulty, - GasLimit, - BaseFee = 8, - BlockHash, - ChainId, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, EnumIter)] -pub enum RwTableTag { - Start = 1, - Stack, - Memory, - AccountStorage, - TxAccessListAccount, - TxAccessListAccountStorage, - TxRefund, - Account, - AccountDestructed, - CallContext, - TxLog, - TxReceipt, -} - -impl RwTableTag { - pub fn is_reversible(self) -> bool { - return matches!( - self, - RwTableTag::TxAccessListAccount - | RwTableTag::TxAccessListAccountStorage - | RwTableTag::TxRefund - | RwTableTag::Account - | RwTableTag::AccountStorage - | RwTableTag::AccountDestructed - ); - } -} - -impl From for usize { - fn from(t: RwTableTag) -> Self { - t as usize - } -} - -#[derive(Clone, Copy, Debug, EnumIter)] -pub enum AccountFieldTag { - Nonce = 1, - Balance, - CodeHash, -} - -#[derive(Clone, Copy, Debug)] -pub enum BytecodeFieldTag { - Length, - Byte, - Padding, -} - -#[derive(Clone, Copy, Debug, PartialEq, EnumIter)] -pub enum TxLogFieldTag { - Address = 1, - Topic, - Data, -} - -#[derive(Clone, Copy, Debug, PartialEq, EnumIter, EnumCount)] -pub enum TxReceiptFieldTag { - PostStateOrStatus = 1, - CumulativeGasUsed, - LogLength, -} - -#[derive(Clone, Copy, Debug, PartialEq, EnumIter)] -pub enum CallContextFieldTag { - RwCounterEndOfReversion = 1, - CallerId, - TxId, - Depth, - CallerAddress, - CalleeAddress, - CallDataOffset, - CallDataLength, - ReturnDataOffset, - ReturnDataLength, - Value, - IsSuccess, - IsPersistent, - IsStatic, - - LastCalleeId, - LastCalleeReturnDataOffset, - LastCalleeReturnDataLength, - - IsRoot, - IsCreate, - CodeHash, - ProgramCounter, - StackPointer, - GasLeft, - MemorySize, - ReversibleWriteCounter, -} - -impl_expr!(FixedTableTag); -// impl_expr!(TxContextFieldTag); -impl_expr!(RwTableTag); -impl_expr!(AccountFieldTag); -impl_expr!(BytecodeFieldTag); -impl_expr!(CallContextFieldTag); -impl_expr!(BlockContextFieldTag); -impl_expr!(TxLogFieldTag); -impl_expr!(TxReceiptFieldTag); - #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, EnumIter)] pub(crate) enum Table { Fixed, @@ -412,58 +292,3 @@ impl Lookup { .unwrap() } } - -// TODO: Move to src/tables.rs -#[derive(Clone, Debug)] -pub struct BlockTable { - pub tag: Column, - pub index: Column, - pub value: Column, -} - -impl BlockTable { - pub fn construct(meta: &mut ConstraintSystem) -> Self { - Self { - tag: meta.advice_column(), - index: meta.advice_column(), - value: meta.advice_column(), - } - } -} - -impl TableColumns for BlockTable { - fn columns(&self) -> Vec> { - vec![self.tag, self.index, self.value] - } -} - -// TODO: Move to src/tables.rs -#[derive(Clone, Debug)] -pub struct KeccakTable { - pub is_enabled: Column, - pub input_rlc: Column, // RLC of input bytes - pub input_len: Column, - pub output_rlc: Column, // RLC of hash of input bytes -} - -impl KeccakTable { - pub fn construct(meta: &mut ConstraintSystem) -> Self { - Self { - is_enabled: meta.advice_column(), - input_rlc: meta.advice_column(), - input_len: meta.advice_column(), - output_rlc: meta.advice_column(), - } - } -} - -impl TableColumns for KeccakTable { - fn columns(&self) -> Vec> { - vec![ - self.is_enabled, - self.input_rlc, - self.input_len, - self.output_rlc, - ] - } -} diff --git a/zkevm-circuits/src/evm_circuit/util/common_gadget.rs b/zkevm-circuits/src/evm_circuit/util/common_gadget.rs index 9c0d2e2f86..2a78960a64 100644 --- a/zkevm-circuits/src/evm_circuit/util/common_gadget.rs +++ b/zkevm-circuits/src/evm_circuit/util/common_gadget.rs @@ -1,8 +1,9 @@ use super::CachedRegion; use crate::{ + table::{AccountFieldTag, CallContextFieldTag, }, evm_circuit::{ param::N_BYTES_GAS, - table::{AccountFieldTag, CallContextFieldTag, FixedTableTag, Lookup}, + table::{ FixedTableTag, Lookup}, util::{ constraint_builder::{ ConstraintBuilder, ReversionInfo, StepStateTransition, diff --git a/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs b/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs index 1d928b3282..dbe41e4a91 100644 --- a/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs +++ b/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs @@ -3,11 +3,15 @@ use crate::{ param::STACK_CAPACITY, step::{ExecutionState, Step}, table::{ - AccountFieldTag, BytecodeFieldTag, CallContextFieldTag, FixedTableTag, Lookup, - RwTableTag, Table, TxContextFieldTag, TxLogFieldTag, TxReceiptFieldTag, + FixedTableTag, Lookup, + Table, }, util::{Cell, RandomLinearCombination, Word}, }, + table::{ + AccountFieldTag, BytecodeFieldTag, CallContextFieldTag, + RwTableTag, TxContextFieldTag, TxLogFieldTag, TxReceiptFieldTag, + }, util::Expr, }; use eth_types::Field; diff --git a/zkevm-circuits/src/evm_circuit/witness.rs b/zkevm-circuits/src/evm_circuit/witness.rs index 835920f843..0168eb02f0 100644 --- a/zkevm-circuits/src/evm_circuit/witness.rs +++ b/zkevm-circuits/src/evm_circuit/witness.rs @@ -1,12 +1,13 @@ #![allow(missing_docs)] -use crate::evm_circuit::{ +use crate::{evm_circuit::{ param::{N_BYTES_WORD, STACK_CAPACITY}, step::ExecutionState, + util::RandomLinearCombination, +}, table::{ AccountFieldTag, BlockContextFieldTag, BytecodeFieldTag, CallContextFieldTag, RwTableTag, TxContextFieldTag, TxLogFieldTag, TxReceiptFieldTag, }, - util::RandomLinearCombination, }; use bus_mapping::{ diff --git a/zkevm-circuits/src/lib.rs b/zkevm-circuits/src/lib.rs index c38d781143..595a1a20db 100644 --- a/zkevm-circuits/src/lib.rs +++ b/zkevm-circuits/src/lib.rs @@ -21,6 +21,7 @@ pub mod evm_circuit; pub mod rw_table; pub mod state_circuit; pub mod super_circuit; +pub mod table; #[cfg(test)] pub mod test_util; pub mod tx_circuit; diff --git a/zkevm-circuits/src/rw_table.rs b/zkevm-circuits/src/rw_table.rs index 9099ba823e..e69de29bb2 100644 --- a/zkevm-circuits/src/rw_table.rs +++ b/zkevm-circuits/src/rw_table.rs @@ -1,82 +0,0 @@ -#![allow(missing_docs)] -use halo2_proofs::{ - arithmetic::FieldExt, - circuit::Region, - plonk::{Advice, Column, ConstraintSystem, Error}, -}; - -use crate::evm_circuit::{table::TableColumns, witness::RwRow}; - -/// The rw table shared between evm circuit and state circuit -#[derive(Clone, Copy)] -pub struct RwTable { - pub rw_counter: Column, - pub is_write: Column, - pub tag: Column, - pub key1: Column, - pub key2: Column, - pub key3: Column, - pub key4: Column, - pub value: Column, - pub value_prev: Column, - pub aux1: Column, - pub aux2: Column, -} - -impl TableColumns for RwTable { - fn columns(&self) -> Vec> { - vec![ - self.rw_counter, - self.is_write, - self.tag, - self.key1, - self.key2, - self.key3, - self.key4, - self.value, - self.value_prev, - self.aux1, - self.aux2, - ] - } -} -impl RwTable { - pub fn construct(meta: &mut ConstraintSystem) -> Self { - Self { - rw_counter: meta.advice_column(), - is_write: meta.advice_column(), - tag: meta.advice_column(), - key1: meta.advice_column(), - key2: meta.advice_column(), - key3: meta.advice_column(), - key4: meta.advice_column(), - value: meta.advice_column(), - value_prev: meta.advice_column(), - aux1: meta.advice_column(), - aux2: meta.advice_column(), - } - } - pub fn assign( - &self, - region: &mut Region<'_, F>, - offset: usize, - row: &RwRow, - ) -> Result<(), Error> { - for (column, value) in [ - (self.rw_counter, row.rw_counter), - (self.is_write, row.is_write), - (self.tag, row.tag), - (self.key1, row.key1), - (self.key2, row.key2), - (self.key3, row.key3), - (self.key4, row.key4), - (self.value, row.value), - (self.value_prev, row.value_prev), - (self.aux1, row.aux1), - (self.aux2, row.aux2), - ] { - region.assign_advice(|| "assign rw row on rw table", column, offset, || Ok(value))?; - } - Ok(()) - } -} diff --git a/zkevm-circuits/src/state_circuit.rs b/zkevm-circuits/src/state_circuit.rs index 8ac3043a7b..287b7cea7a 100644 --- a/zkevm-circuits/src/state_circuit.rs +++ b/zkevm-circuits/src/state_circuit.rs @@ -7,10 +7,11 @@ mod random_linear_combination; #[cfg(test)] mod test; -use crate::evm_circuit::{ +use crate::{evm_circuit::{ param::N_BYTES_WORD, - table::RwTableTag, witness::{Rw, RwMap}, +}, + table::RwTableTag, }; use crate::util::Expr; use constraint_builder::{ConstraintBuilder, Queries}; diff --git a/zkevm-circuits/src/state_circuit/constraint_builder.rs b/zkevm-circuits/src/state_circuit/constraint_builder.rs index 42ccc54187..210e76237a 100644 --- a/zkevm-circuits/src/state_circuit/constraint_builder.rs +++ b/zkevm-circuits/src/state_circuit/constraint_builder.rs @@ -3,10 +3,11 @@ use super::{ random_linear_combination::Queries as RlcQueries, N_LIMBS_ACCOUNT_ADDRESS, N_LIMBS_ID, N_LIMBS_RW_COUNTER, }; -use crate::evm_circuit::{ +use crate::{evm_circuit::{ param::N_BYTES_WORD, - table::{AccountFieldTag, RwTableTag}, util::not, +}, + table::{AccountFieldTag, RwTableTag}, }; use crate::util::Expr; use eth_types::Field; diff --git a/zkevm-circuits/src/state_circuit/lookups.rs b/zkevm-circuits/src/state_circuit/lookups.rs index d90ee9e670..70eeaca760 100644 --- a/zkevm-circuits/src/state_circuit/lookups.rs +++ b/zkevm-circuits/src/state_circuit/lookups.rs @@ -1,4 +1,4 @@ -use crate::evm_circuit::table::CallContextFieldTag; +use crate::table::CallContextFieldTag; use eth_types::Field; use halo2_proofs::{ circuit::Layouter, diff --git a/zkevm-circuits/src/state_circuit/test.rs b/zkevm-circuits/src/state_circuit/test.rs index debf9b7b97..91eb8cc174 100644 --- a/zkevm-circuits/src/state_circuit/test.rs +++ b/zkevm-circuits/src/state_circuit/test.rs @@ -1,7 +1,8 @@ use super::{StateCircuit, StateConfig}; -use crate::evm_circuit::{ - table::{AccountFieldTag, CallContextFieldTag, RwTableTag, TxLogFieldTag, TxReceiptFieldTag}, +use crate::{evm_circuit::{ witness::{Rw, RwMap}, +}, + table::{AccountFieldTag, CallContextFieldTag, RwTableTag, TxLogFieldTag, TxReceiptFieldTag}, }; use bus_mapping::operation::{ MemoryOp, Operation, OperationContainer, RWCounter, StackOp, StorageOp, RW, diff --git a/zkevm-circuits/src/super_circuit.rs b/zkevm-circuits/src/super_circuit.rs index 8cfbff3b66..e9f60b4a88 100644 --- a/zkevm-circuits/src/super_circuit.rs +++ b/zkevm-circuits/src/super_circuit.rs @@ -12,21 +12,17 @@ #![allow(missing_docs)] // use halo2_proofs::plonk::*; -use crate::tx_circuit::{self, TxCircuit, TxCircuitConfig, TxTable}; +use crate::tx_circuit::{self, TxCircuit, TxCircuitConfig}; use crate::bytecode_circuit::bytecode_unroller::{ - unroll, BytecodeTable, Config as BytecodeConfig, UnrolledBytecode, + unroll, Config as BytecodeConfig, UnrolledBytecode, }; -use crate::util::power_of_randomness_from_instance; -use crate::{ - evm_circuit::{ - table::{BlockTable, FixedTableTag, KeccakTable}, - witness::Block, - EvmCircuit, {load_block, load_keccaks, load_rws}, - }, - rw_table::RwTable, +use crate::evm_circuit::{table::FixedTableTag, witness::Block, EvmCircuit}; +use crate::table::{ + load_block, load_keccaks, load_rws, BlockTable, BytecodeTable, KeccakTable, RwTable, TxTable, }; +use crate::util::power_of_randomness_from_instance; use eth_types::Field; use halo2_proofs::{ circuit::{Layouter, SimpleFloorPlanner}, diff --git a/zkevm-circuits/src/table.rs b/zkevm-circuits/src/table.rs new file mode 100644 index 0000000000..032c74d38b --- /dev/null +++ b/zkevm-circuits/src/table.rs @@ -0,0 +1,594 @@ +//! Table definitions used cross-circuits + +use crate::evm_circuit::{witness::RwRow}; +use crate::evm_circuit::{ + util::{rlc, RandomLinearCombination}, + witness::{BlockContext, Bytecode, RwMap, Transaction}, +}; +use itertools::Itertools; +use crate::impl_expr; +use eth_types::{Field, ToLittleEndian, Word}; +use halo2_proofs::{ + arithmetic::FieldExt, + circuit::Region, + plonk::{Advice, Column, ConstraintSystem, Error}, +}; +use halo2_proofs::{circuit::Layouter, plonk::*}; +use keccak256::plain::Keccak; +use strum_macros::{EnumCount, EnumIter}; + +pub trait TableColumns { + fn columns(&self) -> Vec>; +} + +// TODO: Deduplicate with +// `zkevm-circuits/src/evm_circuit/table.rs::TxContextFieldTag`. +/// Tag used to identify each field in the transaction in a row of the +/// transaction table. +#[derive(Clone, Copy, Debug)] +pub enum TxFieldTag { + /// Unused tag + Null = 0, + /// Nonce + Nonce, + /// Gas + Gas, + /// GasPrice + GasPrice, + /// CallerAddress + CallerAddress, + /// CalleeAddress + CalleeAddress, + /// IsCreate + IsCreate, + /// Value + Value, + /// CallDataLength + CallDataLength, + /// Gas cost for transaction call data (4 for byte == 0, 16 otherwise) + CallDataGasCost, + /// TxSignHash: Hash of the transaction without the signature, used for + /// signing. + TxSignHash, + /// CallData + CallData, +} +impl_expr!(TxFieldTag); +pub type TxContextFieldTag = TxFieldTag; + +/// TxTable columns +#[derive(Clone, Debug)] +pub struct TxTable { + pub tx_id: Column, + pub tag: Column, + pub index: Column, + pub value: Column, +} + +impl TxTable { + pub fn construct(meta: &mut ConstraintSystem) -> Self { + Self { + tx_id: meta.advice_column(), + tag: meta.advice_column(), + index: meta.advice_column(), + value: meta.advice_column(), + } + } +} + +impl TableColumns for TxTable { + fn columns(&self) -> Vec> { + vec![self.tx_id, self.tag, self.index, self.value] + } +} + +// TODO: Move to src/tables.rs +pub fn load_txs( + tx_table: &TxTable, + layouter: &mut impl Layouter, + txs: &[Transaction], + randomness: F, +) -> Result<(), Error> { + layouter.assign_region( + || "tx table", + |mut region| { + let mut offset = 0; + for column in tx_table.columns() { + region.assign_advice( + || "tx table all-zero row", + column, + offset, + || Ok(F::zero()), + )?; + } + offset += 1; + + // println!("DBG load_txs"); + let tx_table_columns = tx_table.columns(); + for tx in txs.iter() { + for row in tx.table_assignments(randomness) { + // print!("{:02} ", offset); + for (column, value) in tx_table_columns.iter().zip_eq(row) { + // print!("{:?} ", value); + region.assign_advice( + || format!("tx table row {}", offset), + *column, + offset, + || Ok(value), + )?; + } + offset += 1; + // println!(""); + } + } + Ok(()) + }, + ) +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, EnumIter)] +pub enum RwTableTag { + Start = 1, + Stack, + Memory, + AccountStorage, + TxAccessListAccount, + TxAccessListAccountStorage, + TxRefund, + Account, + AccountDestructed, + CallContext, + TxLog, + TxReceipt, +} +impl_expr!(RwTableTag); + +impl RwTableTag { + pub fn is_reversible(self) -> bool { + return matches!( + self, + RwTableTag::TxAccessListAccount + | RwTableTag::TxAccessListAccountStorage + | RwTableTag::TxRefund + | RwTableTag::Account + | RwTableTag::AccountStorage + | RwTableTag::AccountDestructed + ); + } +} + +impl From for usize { + fn from(t: RwTableTag) -> Self { + t as usize + } +} + +#[derive(Clone, Copy, Debug, EnumIter)] +pub enum AccountFieldTag { + Nonce = 1, + Balance, + CodeHash, +} +impl_expr!(AccountFieldTag); + +#[derive(Clone, Copy, Debug, PartialEq, EnumIter)] +pub enum TxLogFieldTag { + Address = 1, + Topic, + Data, +} +impl_expr!(TxLogFieldTag); + +#[derive(Clone, Copy, Debug, PartialEq, EnumIter, EnumCount)] +pub enum TxReceiptFieldTag { + PostStateOrStatus = 1, + CumulativeGasUsed, + LogLength, +} +impl_expr!(TxReceiptFieldTag); + +#[derive(Clone, Copy, Debug, PartialEq, EnumIter)] +pub enum CallContextFieldTag { + RwCounterEndOfReversion = 1, + CallerId, + TxId, + Depth, + CallerAddress, + CalleeAddress, + CallDataOffset, + CallDataLength, + ReturnDataOffset, + ReturnDataLength, + Value, + IsSuccess, + IsPersistent, + IsStatic, + + LastCalleeId, + LastCalleeReturnDataOffset, + LastCalleeReturnDataLength, + + IsRoot, + IsCreate, + CodeHash, + ProgramCounter, + StackPointer, + GasLeft, + MemorySize, + ReversibleWriteCounter, +} +impl_expr!(CallContextFieldTag); + +/// The rw table shared between evm circuit and state circuit +#[derive(Clone, Copy)] +pub struct RwTable { + pub rw_counter: Column, + pub is_write: Column, + pub tag: Column, + pub key1: Column, + pub key2: Column, + pub key3: Column, + pub key4: Column, + pub value: Column, + pub value_prev: Column, + pub aux1: Column, + pub aux2: Column, +} + +impl TableColumns for RwTable { + fn columns(&self) -> Vec> { + vec![ + self.rw_counter, + self.is_write, + self.tag, + self.key1, + self.key2, + self.key3, + self.key4, + self.value, + self.value_prev, + self.aux1, + self.aux2, + ] + } +} +impl RwTable { + pub fn construct(meta: &mut ConstraintSystem) -> Self { + Self { + rw_counter: meta.advice_column(), + is_write: meta.advice_column(), + tag: meta.advice_column(), + key1: meta.advice_column(), + key2: meta.advice_column(), + key3: meta.advice_column(), + key4: meta.advice_column(), + value: meta.advice_column(), + value_prev: meta.advice_column(), + aux1: meta.advice_column(), + aux2: meta.advice_column(), + } + } + pub fn assign( + &self, + region: &mut Region<'_, F>, + offset: usize, + row: &RwRow, + ) -> Result<(), Error> { + for (column, value) in [ + (self.rw_counter, row.rw_counter), + (self.is_write, row.is_write), + (self.tag, row.tag), + (self.key1, row.key1), + (self.key2, row.key2), + (self.key3, row.key3), + (self.key4, row.key4), + (self.value, row.value), + (self.value_prev, row.value_prev), + (self.aux1, row.aux1), + (self.aux2, row.aux2), + ] { + region.assign_advice(|| "assign rw row on rw table", column, offset, || Ok(value))?; + } + Ok(()) + } +} + +// TODO: Move to src/tables.rs +pub fn load_rws( + rw_table: &RwTable, + layouter: &mut impl Layouter, + rws: &RwMap, + randomness: F, +) -> Result<(), Error> { + layouter.assign_region( + || "rw table", + |mut region| { + let mut offset = 0; + rw_table.assign(&mut region, offset, &Default::default())?; + offset += 1; + + let mut rows = rws + .0 + .values() + .flat_map(|rws| rws.iter()) + .collect::>(); + + rows.sort_by_key(|a| a.rw_counter()); + let mut expected_rw_counter = 1; + for rw in rows { + assert!(rw.rw_counter() == expected_rw_counter); + expected_rw_counter += 1; + + rw_table.assign(&mut region, offset, &rw.table_assignment(randomness))?; + offset += 1; + } + Ok(()) + }, + ) +} + +#[derive(Clone, Copy, Debug)] +pub enum BytecodeFieldTag { + Length, + Byte, + Padding, +} +impl_expr!(BytecodeFieldTag); + +// CHANGELOG: Added BytecodeTable to help reusing the table config with other +// circuits +#[derive(Clone, Debug)] +pub struct BytecodeTable { + pub code_hash: Column, // CHANGELOG: Renamed from hash + pub tag: Column, + pub index: Column, + pub is_code: Column, + pub value: Column, +} + +impl BytecodeTable { + pub fn construct(meta: &mut ConstraintSystem) -> Self { + Self { + code_hash: meta.advice_column(), + tag: meta.advice_column(), + index: meta.advice_column(), + is_code: meta.advice_column(), + value: meta.advice_column(), + } + } +} + +impl TableColumns for BytecodeTable { + fn columns(&self) -> Vec> { + vec![ + self.code_hash, + self.tag, + self.index, + self.is_code, + self.value, + ] + } +} + +// use crate::util::TableShow; + +// TODO: Move to src/tables.rs +pub fn load_bytecodes<'a, F: Field>( + bytecode_table: &BytecodeTable, + layouter: &mut impl Layouter, + bytecodes: impl IntoIterator + Clone, + randomness: F, +) -> Result<(), Error> { + // println!("> load_bytecodes"); + // let mut table = TableShow::::new(vec!["codeHash", "tag", "index", + // "isCode", "value"]); + layouter.assign_region( + || "bytecode table", + |mut region| { + let mut offset = 0; + for column in bytecode_table.columns() { + region.assign_advice( + || "bytecode table all-zero row", + column, + offset, + || Ok(F::zero()), + )?; + } + offset += 1; + + let bytecode_table_columns = bytecode_table.columns(); + for bytecode in bytecodes.clone() { + for row in bytecode.table_assignments(randomness) { + // let mut column_index = 0; + for (column, value) in bytecode_table_columns.iter().zip_eq(row) { + region.assign_advice( + || format!("bytecode table row {}", offset), + *column, + offset, + || Ok(value), + )?; + // table.push(column_index, value); + // column_index += 1; + } + offset += 1; + } + } + // table.print(); + Ok(()) + }, + ) +} + +// Keep the sequence consistent with OpcodeId for scalar +#[derive(Clone, Copy, Debug)] +pub enum BlockContextFieldTag { + Coinbase = 1, + Timestamp, + Number, + Difficulty, + GasLimit, + BaseFee = 8, + BlockHash, + ChainId, +} +impl_expr!(BlockContextFieldTag); + +// TODO: Move to src/tables.rs +#[derive(Clone, Debug)] +pub struct BlockTable { + pub tag: Column, + pub index: Column, + pub value: Column, +} + +impl BlockTable { + pub fn construct(meta: &mut ConstraintSystem) -> Self { + Self { + tag: meta.advice_column(), + index: meta.advice_column(), + value: meta.advice_column(), + } + } +} + +impl TableColumns for BlockTable { + fn columns(&self) -> Vec> { + vec![self.tag, self.index, self.value] + } +} + +// TODO: Move to src/tables.rs +pub fn load_block( + block_table: &BlockTable, + layouter: &mut impl Layouter, + block: &BlockContext, + randomness: F, +) -> Result<(), Error> { + layouter.assign_region( + || "block table", + |mut region| { + let mut offset = 0; + for column in block_table.columns() { + region.assign_advice( + || "block table all-zero row", + column, + offset, + || Ok(F::zero()), + )?; + } + offset += 1; + + let block_table_columns = block_table.columns(); + for row in block.table_assignments(randomness) { + for (column, value) in block_table_columns.iter().zip_eq(row) { + region.assign_advice( + || format!("block table row {}", offset), + *column, + offset, + || Ok(value), + )?; + } + offset += 1; + } + + Ok(()) + }, + ) +} + +// TODO: Move to src/tables.rs +#[derive(Clone, Debug)] +pub struct KeccakTable { + pub is_enabled: Column, + pub input_rlc: Column, // RLC of input bytes + pub input_len: Column, + pub output_rlc: Column, // RLC of hash of input bytes +} + +impl KeccakTable { + pub fn construct(meta: &mut ConstraintSystem) -> Self { + Self { + is_enabled: meta.advice_column(), + input_rlc: meta.advice_column(), + input_len: meta.advice_column(), + output_rlc: meta.advice_column(), + } + } +} + +impl TableColumns for KeccakTable { + fn columns(&self) -> Vec> { + vec![ + self.is_enabled, + self.input_rlc, + self.input_len, + self.output_rlc, + ] + } +} + +pub fn keccak_table_assignments(input: &[u8], randomness: F) -> Vec<[F; 4]> { + // CHANGELOG: Using `RLC(reversed(input))` + let input_rlc: F = rlc::value(input.iter().rev(), randomness); + let input_len = F::from(input.len() as u64); + let mut keccak = Keccak::default(); + keccak.update(input); + let output = keccak.digest(); + let output_rlc = RandomLinearCombination::::random_linear_combine( + Word::from_big_endian(output.as_slice()).to_le_bytes(), + randomness, + ); + + vec![[F::one(), input_rlc, input_len, output_rlc]] +} + +// NOTE: For now, the input_rlc of the keccak is defined as +// `RLC(reversed(input))` for convenience of the circuits that do the lookups. +// This allows calculating the `input_rlc` after all the inputs bytes have been +// layed out via the pattern `acc[i] = acc[i-1] * r + value[i]`. +pub fn load_keccaks<'a, F: Field>( + keccak_table: &KeccakTable, + layouter: &mut impl Layouter, + inputs: impl IntoIterator + Clone, + randomness: F, +) -> Result<(), Error> { + // println!("> super_circuit.load_keccaks"); + // let mut table = TableShow::::new(vec!["is_enabled", "input_rlc", + // "input_len", "output_rlc"]); + layouter.assign_region( + || "keccak table", + |mut region| { + let mut offset = 0; + for column in keccak_table.columns() { + region.assign_advice( + || "keccak table all-zero row", + column, + offset, + || Ok(F::zero()), + )?; + } + offset += 1; + + let keccak_table_columns = keccak_table.columns(); + for input in inputs.clone() { + // println!("+ {:?}", input); + for row in keccak_table_assignments(input, randomness) { + // let mut column_index = 0; + for (column, value) in keccak_table_columns.iter().zip_eq(row) { + region.assign_advice( + || format!("keccak table row {}", offset), + *column, + offset, + || Ok(value), + )?; + // table.push(column_index, value); + // column_index += 1; + } + offset += 1; + } + } + // table.print(); + Ok(()) + }, + ) +} diff --git a/zkevm-circuits/src/tx_circuit.rs b/zkevm-circuits/src/tx_circuit.rs index ef17f6e1ee..2797d132a9 100644 --- a/zkevm-circuits/src/tx_circuit.rs +++ b/zkevm-circuits/src/tx_circuit.rs @@ -8,11 +8,7 @@ pub mod sign_verify; -use crate::evm_circuit::{ - load_keccaks, - table::{KeccakTable, TableColumns}, -}; -use crate::impl_expr; +use crate::table::{load_keccaks, KeccakTable, TxFieldTag, TxTable}; use crate::util::{power_of_randomness_from_instance, random_linear_combine_word as rlc}; use eth_types::{ geth_types::Transaction, Address, Field, ToBigEndian, ToLittleEndian, ToScalar, Word, @@ -155,41 +151,6 @@ fn tx_to_sign_data(tx: &Transaction, chain_id: u64) -> Result { }) } -// TODO: Deduplicate with -// `zkevm-circuits/src/evm_circuit/table.rs::TxContextFieldTag`. -/// Tag used to identify each field in the transaction in a row of the -/// transaction table. -#[derive(Clone, Copy, Debug)] -pub enum TxFieldTag { - /// Unused tag - Null = 0, - /// Nonce - Nonce, - /// Gas - Gas, - /// GasPrice - GasPrice, - /// CallerAddress - CallerAddress, - /// CalleeAddress - CalleeAddress, - /// IsCreate - IsCreate, - /// Value - Value, - /// CallDataLength - CallDataLength, - /// Gas cost for transaction call data (4 for byte == 0, 16 otherwise) - CallDataGasCost, - /// TxSignHash: Hash of the transaction without the signature, used for - /// signing. - TxSignHash, - /// CallData - CallData, -} - -impl_expr!(TxFieldTag); - /// Config for TxCircuit #[derive(Clone, Debug)] pub struct TxCircuitConfig { @@ -202,32 +163,6 @@ pub struct TxCircuitConfig { _marker: PhantomData, } -/// TxTable columns -#[derive(Clone, Debug)] -pub struct TxTable { - pub tx_id: Column, - pub tag: Column, - pub index: Column, - pub value: Column, -} - -impl TxTable { - pub fn construct(meta: &mut ConstraintSystem) -> Self { - Self { - tx_id: meta.advice_column(), - tag: meta.advice_column(), - index: meta.advice_column(), - value: meta.advice_column(), - } - } -} - -impl TableColumns for TxTable { - fn columns(&self) -> Vec> { - vec![self.tx_id, self.tag, self.index, self.value] - } -} - impl TxCircuitConfig { pub fn new( meta: &mut ConstraintSystem, diff --git a/zkevm-circuits/src/tx_circuit/sign_verify.rs b/zkevm-circuits/src/tx_circuit/sign_verify.rs index 74caf84459..7ee93182c9 100644 --- a/zkevm-circuits/src/tx_circuit/sign_verify.rs +++ b/zkevm-circuits/src/tx_circuit/sign_verify.rs @@ -6,10 +6,9 @@ use crate::{ evm_circuit::{ - load_keccaks, - table::KeccakTable, util::{not, RandomLinearCombination, Word}, }, + table::{load_keccaks, KeccakTable}, util::Expr, }; use ecc::{EccConfig, GeneralEccChip}; From 3197b2295c42b36a379989fcffd4a944ebd7423f Mon Sep 17 00:00:00 2001 From: Eduard S Date: Mon, 18 Jul 2022 16:31:27 +0200 Subject: [PATCH 17/26] cargo fmt --- .../src/evm_circuit/execution/block_ctx.rs | 2 +- .../src/evm_circuit/execution/calldatacopy.rs | 2 +- .../src/evm_circuit/execution/calldataload.rs | 2 +- .../src/evm_circuit/execution/calldatasize.rs | 2 +- .../src/evm_circuit/execution/caller.rs | 2 +- .../src/evm_circuit/execution/callvalue.rs | 2 +- .../src/evm_circuit/execution/chainid.rs | 2 +- .../execution/copy_code_to_memory.rs | 10 +++++----- .../src/evm_circuit/execution/copy_to_log.rs | 15 ++++++++------- .../src/evm_circuit/execution/end_tx.rs | 7 +++---- .../src/evm_circuit/execution/extcodehash.rs | 2 +- .../src/evm_circuit/execution/gasprice.rs | 2 +- .../src/evm_circuit/execution/logs.rs | 2 +- .../src/evm_circuit/execution/memory_copy.rs | 19 ++++++++++--------- .../src/evm_circuit/execution/origin.rs | 2 +- .../src/evm_circuit/execution/selfbalance.rs | 2 +- .../src/evm_circuit/execution/sload.rs | 2 +- .../src/evm_circuit/execution/sstore.rs | 2 +- .../src/evm_circuit/execution/stop.rs | 2 +- .../src/evm_circuit/util/common_gadget.rs | 4 ++-- .../evm_circuit/util/constraint_builder.rs | 13 +++++-------- zkevm-circuits/src/evm_circuit/witness.rs | 11 ++++++----- zkevm-circuits/src/rw_table.rs | 1 + zkevm-circuits/src/state_circuit.rs | 11 ++++++----- .../src/state_circuit/constraint_builder.rs | 8 +++----- zkevm-circuits/src/state_circuit/test.rs | 5 ++--- zkevm-circuits/src/table.rs | 6 +++--- zkevm-circuits/src/tx_circuit/sign_verify.rs | 6 ++---- 28 files changed, 71 insertions(+), 75 deletions(-) diff --git a/zkevm-circuits/src/evm_circuit/execution/block_ctx.rs b/zkevm-circuits/src/evm_circuit/execution/block_ctx.rs index 8be3c2a657..35791e8164 100644 --- a/zkevm-circuits/src/evm_circuit/execution/block_ctx.rs +++ b/zkevm-circuits/src/evm_circuit/execution/block_ctx.rs @@ -10,7 +10,7 @@ use crate::{ }, witness::{Block, Call, ExecStep, Transaction}, }, - table::BlockContextFieldTag, + table::BlockContextFieldTag, util::Expr, }; use bus_mapping::evm::OpcodeId; diff --git a/zkevm-circuits/src/evm_circuit/execution/calldatacopy.rs b/zkevm-circuits/src/evm_circuit/execution/calldatacopy.rs index cdbcc5de67..b3e2258878 100644 --- a/zkevm-circuits/src/evm_circuit/execution/calldatacopy.rs +++ b/zkevm-circuits/src/evm_circuit/execution/calldatacopy.rs @@ -15,7 +15,7 @@ use crate::{ }, witness::{Block, Call, ExecStep, Transaction}, }, - table::CallContextFieldTag, + table::CallContextFieldTag, util::Expr, }; use bus_mapping::evm::OpcodeId; diff --git a/zkevm-circuits/src/evm_circuit/execution/calldataload.rs b/zkevm-circuits/src/evm_circuit/execution/calldataload.rs index eacf96a3ba..f392c3f75f 100644 --- a/zkevm-circuits/src/evm_circuit/execution/calldataload.rs +++ b/zkevm-circuits/src/evm_circuit/execution/calldataload.rs @@ -5,7 +5,6 @@ use eth_types::{Field, ToLittleEndian}; use halo2_proofs::plonk::{Error, Expression}; use crate::{ - table::{CallContextFieldTag, TxContextFieldTag}, evm_circuit::{ param::{N_BYTES_MEMORY_ADDRESS, N_BYTES_WORD}, step::ExecutionState, @@ -18,6 +17,7 @@ use crate::{ }, witness::{Block, Call, ExecStep, Transaction}, }, + table::{CallContextFieldTag, TxContextFieldTag}, util::Expr, }; diff --git a/zkevm-circuits/src/evm_circuit/execution/calldatasize.rs b/zkevm-circuits/src/evm_circuit/execution/calldatasize.rs index a80f2d001b..52345b9704 100644 --- a/zkevm-circuits/src/evm_circuit/execution/calldatasize.rs +++ b/zkevm-circuits/src/evm_circuit/execution/calldatasize.rs @@ -1,5 +1,4 @@ use crate::{ - table::CallContextFieldTag, evm_circuit::{ execution::ExecutionGadget, param::N_BYTES_CALLDATASIZE, @@ -11,6 +10,7 @@ use crate::{ }, witness::{Block, Call, ExecStep, Transaction}, }, + table::CallContextFieldTag, util::Expr, }; use bus_mapping::evm::OpcodeId; diff --git a/zkevm-circuits/src/evm_circuit/execution/caller.rs b/zkevm-circuits/src/evm_circuit/execution/caller.rs index 1a67356bd8..fc6577b62e 100644 --- a/zkevm-circuits/src/evm_circuit/execution/caller.rs +++ b/zkevm-circuits/src/evm_circuit/execution/caller.rs @@ -1,5 +1,4 @@ use crate::{ - table::CallContextFieldTag, evm_circuit::{ execution::ExecutionGadget, param::N_BYTES_ACCOUNT_ADDRESS, @@ -11,6 +10,7 @@ use crate::{ }, witness::{Block, Call, ExecStep, Transaction}, }, + table::CallContextFieldTag, util::Expr, }; use bus_mapping::evm::OpcodeId; diff --git a/zkevm-circuits/src/evm_circuit/execution/callvalue.rs b/zkevm-circuits/src/evm_circuit/execution/callvalue.rs index 1ed909d33a..47e2ed0153 100644 --- a/zkevm-circuits/src/evm_circuit/execution/callvalue.rs +++ b/zkevm-circuits/src/evm_circuit/execution/callvalue.rs @@ -1,5 +1,4 @@ use crate::{ - table::CallContextFieldTag, evm_circuit::{ execution::ExecutionGadget, step::ExecutionState, @@ -10,6 +9,7 @@ use crate::{ }, witness::{Block, Call, ExecStep, Transaction}, }, + table::CallContextFieldTag, util::Expr, }; use bus_mapping::evm::OpcodeId; diff --git a/zkevm-circuits/src/evm_circuit/execution/chainid.rs b/zkevm-circuits/src/evm_circuit/execution/chainid.rs index 1d4ed3f2b3..a7fe6b0228 100644 --- a/zkevm-circuits/src/evm_circuit/execution/chainid.rs +++ b/zkevm-circuits/src/evm_circuit/execution/chainid.rs @@ -1,5 +1,4 @@ use crate::{ - table::BlockContextFieldTag, evm_circuit::{ execution::ExecutionGadget, step::ExecutionState, @@ -10,6 +9,7 @@ use crate::{ }, witness::{Block, Call, ExecStep, Transaction}, }, + table::BlockContextFieldTag, util::Expr, }; use bus_mapping::evm::OpcodeId; diff --git a/zkevm-circuits/src/evm_circuit/execution/copy_code_to_memory.rs b/zkevm-circuits/src/evm_circuit/execution/copy_code_to_memory.rs index 9765562518..72914aaf1e 100644 --- a/zkevm-circuits/src/evm_circuit/execution/copy_code_to_memory.rs +++ b/zkevm-circuits/src/evm_circuit/execution/copy_code_to_memory.rs @@ -262,12 +262,12 @@ pub(crate) mod test { use crate::{ evm_circuit::{ - step::ExecutionState, - test::run_test_circuit_incomplete_fixed_table, - witness::{Block, Bytecode, Call, ExecStep, Rw, RwMap, Transaction}, - }, + step::ExecutionState, + test::run_test_circuit_incomplete_fixed_table, + witness::{Block, Bytecode, Call, ExecStep, Rw, RwMap, Transaction}, + }, table::RwTableTag, -}; + }; #[allow(clippy::too_many_arguments)] pub(crate) fn make_copy_code_step( diff --git a/zkevm-circuits/src/evm_circuit/execution/copy_to_log.rs b/zkevm-circuits/src/evm_circuit/execution/copy_to_log.rs index aafba441d5..e89fdaac3c 100644 --- a/zkevm-circuits/src/evm_circuit/execution/copy_to_log.rs +++ b/zkevm-circuits/src/evm_circuit/execution/copy_to_log.rs @@ -11,7 +11,7 @@ use crate::{ }, witness::{Block, Call, ExecStep, Transaction}, }, - table::TxLogFieldTag, + table::TxLogFieldTag, util::Expr, }; use bus_mapping::{circuit_input_builder::CopyDetails, constants::MAX_COPY_BYTES}; @@ -229,13 +229,14 @@ impl ExecutionGadget for CopyToLogGadget { #[cfg(test)] pub mod test { - use crate::{evm_circuit::{ - step::ExecutionState, - test::{rand_bytes, run_test_circuit_incomplete_fixed_table}, - witness::{Block, Bytecode, Call, ExecStep, Rw, RwMap, Transaction}, - }, + use crate::{ + evm_circuit::{ + step::ExecutionState, + test::{rand_bytes, run_test_circuit_incomplete_fixed_table}, + witness::{Block, Bytecode, Call, ExecStep, Rw, RwMap, Transaction}, + }, table::{RwTableTag, TxLogFieldTag}, -}; + }; use bus_mapping::{ circuit_input_builder::{CopyDetails, StepAuxiliaryData}, constants::MAX_COPY_BYTES, diff --git a/zkevm-circuits/src/evm_circuit/execution/end_tx.rs b/zkevm-circuits/src/evm_circuit/execution/end_tx.rs index df9a0fd0f7..4b5f862a78 100644 --- a/zkevm-circuits/src/evm_circuit/execution/end_tx.rs +++ b/zkevm-circuits/src/evm_circuit/execution/end_tx.rs @@ -1,8 +1,4 @@ use crate::{ - table::{ - BlockContextFieldTag, CallContextFieldTag, RwTableTag, TxContextFieldTag, - TxReceiptFieldTag, - }, evm_circuit::{ execution::ExecutionGadget, param::N_BYTES_GAS, @@ -18,6 +14,9 @@ use crate::{ }, witness::{Block, Call, ExecStep, Transaction}, }, + table::{ + BlockContextFieldTag, CallContextFieldTag, RwTableTag, TxContextFieldTag, TxReceiptFieldTag, + }, util::Expr, }; use eth_types::{evm_types::MAX_REFUND_QUOTIENT_OF_GAS_USED, Field, ToScalar}; diff --git a/zkevm-circuits/src/evm_circuit/execution/extcodehash.rs b/zkevm-circuits/src/evm_circuit/execution/extcodehash.rs index 51cb42cf1c..2852f9788c 100644 --- a/zkevm-circuits/src/evm_circuit/execution/extcodehash.rs +++ b/zkevm-circuits/src/evm_circuit/execution/extcodehash.rs @@ -1,5 +1,4 @@ use crate::{ - table::{AccountFieldTag, CallContextFieldTag}, evm_circuit::{ execution::ExecutionGadget, param::N_BYTES_ACCOUNT_ADDRESS, @@ -15,6 +14,7 @@ use crate::{ }, witness::{Block, Call, ExecStep, Transaction}, }, + table::{AccountFieldTag, CallContextFieldTag}, util::Expr, }; use eth_types::{evm_types::GasCost, Field, ToAddress, ToScalar, U256}; diff --git a/zkevm-circuits/src/evm_circuit/execution/gasprice.rs b/zkevm-circuits/src/evm_circuit/execution/gasprice.rs index 0dcfb6dd0f..301a3de657 100644 --- a/zkevm-circuits/src/evm_circuit/execution/gasprice.rs +++ b/zkevm-circuits/src/evm_circuit/execution/gasprice.rs @@ -1,5 +1,4 @@ use crate::{ - table::{CallContextFieldTag, TxContextFieldTag}, evm_circuit::{ execution::ExecutionGadget, step::ExecutionState, @@ -10,6 +9,7 @@ use crate::{ }, witness::{Block, Call, ExecStep, Transaction}, }, + table::{CallContextFieldTag, TxContextFieldTag}, util::Expr, }; use bus_mapping::evm::OpcodeId; diff --git a/zkevm-circuits/src/evm_circuit/execution/logs.rs b/zkevm-circuits/src/evm_circuit/execution/logs.rs index 13690fc158..e00438f2f3 100644 --- a/zkevm-circuits/src/evm_circuit/execution/logs.rs +++ b/zkevm-circuits/src/evm_circuit/execution/logs.rs @@ -1,5 +1,4 @@ use crate::{ - table::{CallContextFieldTag, RwTableTag, TxLogFieldTag}, evm_circuit::{ execution::ExecutionGadget, param::N_BYTES_MEMORY_WORD_SIZE, @@ -16,6 +15,7 @@ use crate::{ }, witness::{Block, Call, ExecStep, Transaction}, }, + table::{CallContextFieldTag, RwTableTag, TxLogFieldTag}, util::Expr, }; use array_init::array_init; diff --git a/zkevm-circuits/src/evm_circuit/execution/memory_copy.rs b/zkevm-circuits/src/evm_circuit/execution/memory_copy.rs index c1d57c58f0..e0ed7bba91 100644 --- a/zkevm-circuits/src/evm_circuit/execution/memory_copy.rs +++ b/zkevm-circuits/src/evm_circuit/execution/memory_copy.rs @@ -1,5 +1,4 @@ use crate::{ - table::TxContextFieldTag, evm_circuit::{ execution::ExecutionGadget, param::{N_BYTES_MEMORY_ADDRESS, N_BYTES_MEMORY_WORD_SIZE}, @@ -12,6 +11,7 @@ use crate::{ }, witness::{Block, Call, ExecStep, Transaction}, }, + table::TxContextFieldTag, util::Expr, }; use bus_mapping::{circuit_input_builder::CopyDetails, constants::MAX_COPY_BYTES}; @@ -235,14 +235,15 @@ impl ExecutionGadget for CopyToMemoryGadget { #[cfg(test)] pub mod test { - use crate::{evm_circuit::{ - execution::memory_copy::MAX_COPY_BYTES, - step::ExecutionState, - test::{rand_bytes, run_test_circuit_incomplete_fixed_table}, - witness::{Block, Bytecode, Call, ExecStep, Rw, RwMap, Transaction}, - }, - table::RwTableTag, -}; + use crate::{ + evm_circuit::{ + execution::memory_copy::MAX_COPY_BYTES, + step::ExecutionState, + test::{rand_bytes, run_test_circuit_incomplete_fixed_table}, + witness::{Block, Bytecode, Call, ExecStep, Rw, RwMap, Transaction}, + }, + table::RwTableTag, + }; use bus_mapping::circuit_input_builder::{CopyDetails, StepAuxiliaryData}; use eth_types::evm_types::OpcodeId; use halo2_proofs::arithmetic::BaseExt; diff --git a/zkevm-circuits/src/evm_circuit/execution/origin.rs b/zkevm-circuits/src/evm_circuit/execution/origin.rs index 988ab43e42..acd5a69b1b 100644 --- a/zkevm-circuits/src/evm_circuit/execution/origin.rs +++ b/zkevm-circuits/src/evm_circuit/execution/origin.rs @@ -1,5 +1,4 @@ use crate::{ - table::{CallContextFieldTag, TxContextFieldTag}, evm_circuit::{ execution::ExecutionGadget, param::N_BYTES_ACCOUNT_ADDRESS, @@ -11,6 +10,7 @@ use crate::{ }, witness::{Block, Call, ExecStep, Transaction}, }, + table::{CallContextFieldTag, TxContextFieldTag}, util::Expr, }; use bus_mapping::evm::OpcodeId; diff --git a/zkevm-circuits/src/evm_circuit/execution/selfbalance.rs b/zkevm-circuits/src/evm_circuit/execution/selfbalance.rs index 91b751efe4..06b62a3b69 100644 --- a/zkevm-circuits/src/evm_circuit/execution/selfbalance.rs +++ b/zkevm-circuits/src/evm_circuit/execution/selfbalance.rs @@ -1,5 +1,4 @@ use crate::{ - table::{AccountFieldTag, CallContextFieldTag}, evm_circuit::{ execution::ExecutionGadget, step::ExecutionState, @@ -10,6 +9,7 @@ use crate::{ }, witness::{Block, Call, ExecStep, Transaction}, }, + table::{AccountFieldTag, CallContextFieldTag}, util::Expr, }; use bus_mapping::evm::OpcodeId; diff --git a/zkevm-circuits/src/evm_circuit/execution/sload.rs b/zkevm-circuits/src/evm_circuit/execution/sload.rs index 22230c919d..d17b29915c 100644 --- a/zkevm-circuits/src/evm_circuit/execution/sload.rs +++ b/zkevm-circuits/src/evm_circuit/execution/sload.rs @@ -1,5 +1,4 @@ use crate::{ - table::CallContextFieldTag, evm_circuit::{ execution::ExecutionGadget, step::ExecutionState, @@ -12,6 +11,7 @@ use crate::{ }, witness::{Block, Call, ExecStep, Transaction}, }, + table::CallContextFieldTag, util::Expr, }; use eth_types::{evm_types::GasCost, Field, ToLittleEndian, ToScalar}; diff --git a/zkevm-circuits/src/evm_circuit/execution/sstore.rs b/zkevm-circuits/src/evm_circuit/execution/sstore.rs index 0970e84bf4..81558315b1 100644 --- a/zkevm-circuits/src/evm_circuit/execution/sstore.rs +++ b/zkevm-circuits/src/evm_circuit/execution/sstore.rs @@ -1,5 +1,4 @@ use crate::{ - table::CallContextFieldTag, evm_circuit::{ execution::ExecutionGadget, step::ExecutionState, @@ -13,6 +12,7 @@ use crate::{ }, witness::{Block, Call, ExecStep, Transaction}, }, + table::CallContextFieldTag, util::Expr, }; diff --git a/zkevm-circuits/src/evm_circuit/execution/stop.rs b/zkevm-circuits/src/evm_circuit/execution/stop.rs index d19de77624..14c2b88ed3 100644 --- a/zkevm-circuits/src/evm_circuit/execution/stop.rs +++ b/zkevm-circuits/src/evm_circuit/execution/stop.rs @@ -1,5 +1,4 @@ use crate::{ - table::CallContextFieldTag, evm_circuit::{ execution::ExecutionGadget, step::ExecutionState, @@ -14,6 +13,7 @@ use crate::{ }, witness::{Block, Call, ExecStep, Transaction}, }, + table::CallContextFieldTag, util::Expr, }; use bus_mapping::evm::OpcodeId; diff --git a/zkevm-circuits/src/evm_circuit/util/common_gadget.rs b/zkevm-circuits/src/evm_circuit/util/common_gadget.rs index 2a78960a64..269eb18cd7 100644 --- a/zkevm-circuits/src/evm_circuit/util/common_gadget.rs +++ b/zkevm-circuits/src/evm_circuit/util/common_gadget.rs @@ -1,9 +1,8 @@ use super::CachedRegion; use crate::{ - table::{AccountFieldTag, CallContextFieldTag, }, evm_circuit::{ param::N_BYTES_GAS, - table::{ FixedTableTag, Lookup}, + table::{FixedTableTag, Lookup}, util::{ constraint_builder::{ ConstraintBuilder, ReversionInfo, StepStateTransition, @@ -14,6 +13,7 @@ use crate::{ }, witness::{Block, Call, ExecStep}, }, + table::{AccountFieldTag, CallContextFieldTag}, util::Expr, }; use eth_types::{Field, ToLittleEndian, ToScalar, U256}; diff --git a/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs b/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs index dbe41e4a91..9eb55f2f70 100644 --- a/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs +++ b/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs @@ -2,16 +2,13 @@ use crate::{ evm_circuit::{ param::STACK_CAPACITY, step::{ExecutionState, Step}, - table::{ - FixedTableTag, Lookup, - Table, - }, + table::{FixedTableTag, Lookup, Table}, util::{Cell, RandomLinearCombination, Word}, }, - table::{ - AccountFieldTag, BytecodeFieldTag, CallContextFieldTag, - RwTableTag, TxContextFieldTag, TxLogFieldTag, TxReceiptFieldTag, - }, + table::{ + AccountFieldTag, BytecodeFieldTag, CallContextFieldTag, RwTableTag, TxContextFieldTag, + TxLogFieldTag, TxReceiptFieldTag, + }, util::Expr, }; use eth_types::Field; diff --git a/zkevm-circuits/src/evm_circuit/witness.rs b/zkevm-circuits/src/evm_circuit/witness.rs index 0168eb02f0..a05622329c 100644 --- a/zkevm-circuits/src/evm_circuit/witness.rs +++ b/zkevm-circuits/src/evm_circuit/witness.rs @@ -1,9 +1,10 @@ #![allow(missing_docs)] -use crate::{evm_circuit::{ - param::{N_BYTES_WORD, STACK_CAPACITY}, - step::ExecutionState, - util::RandomLinearCombination, -}, +use crate::{ + evm_circuit::{ + param::{N_BYTES_WORD, STACK_CAPACITY}, + step::ExecutionState, + util::RandomLinearCombination, + }, table::{ AccountFieldTag, BlockContextFieldTag, BytecodeFieldTag, CallContextFieldTag, RwTableTag, TxContextFieldTag, TxLogFieldTag, TxReceiptFieldTag, diff --git a/zkevm-circuits/src/rw_table.rs b/zkevm-circuits/src/rw_table.rs index e69de29bb2..8b13789179 100644 --- a/zkevm-circuits/src/rw_table.rs +++ b/zkevm-circuits/src/rw_table.rs @@ -0,0 +1 @@ + diff --git a/zkevm-circuits/src/state_circuit.rs b/zkevm-circuits/src/state_circuit.rs index 287b7cea7a..b3c1a8b607 100644 --- a/zkevm-circuits/src/state_circuit.rs +++ b/zkevm-circuits/src/state_circuit.rs @@ -7,13 +7,14 @@ mod random_linear_combination; #[cfg(test)] mod test; -use crate::{evm_circuit::{ - param::N_BYTES_WORD, - witness::{Rw, RwMap}, -}, +use crate::util::Expr; +use crate::{ + evm_circuit::{ + param::N_BYTES_WORD, + witness::{Rw, RwMap}, + }, table::RwTableTag, }; -use crate::util::Expr; use constraint_builder::{ConstraintBuilder, Queries}; use eth_types::{Address, Field}; use gadgets::binary_number::{BinaryNumberChip, BinaryNumberConfig}; diff --git a/zkevm-circuits/src/state_circuit/constraint_builder.rs b/zkevm-circuits/src/state_circuit/constraint_builder.rs index 210e76237a..f5a84b7611 100644 --- a/zkevm-circuits/src/state_circuit/constraint_builder.rs +++ b/zkevm-circuits/src/state_circuit/constraint_builder.rs @@ -3,13 +3,11 @@ use super::{ random_linear_combination::Queries as RlcQueries, N_LIMBS_ACCOUNT_ADDRESS, N_LIMBS_ID, N_LIMBS_RW_COUNTER, }; -use crate::{evm_circuit::{ - param::N_BYTES_WORD, - util::not, -}, +use crate::util::Expr; +use crate::{ + evm_circuit::{param::N_BYTES_WORD, util::not}, table::{AccountFieldTag, RwTableTag}, }; -use crate::util::Expr; use eth_types::Field; use gadgets::binary_number::BinaryNumberConfig; use halo2_proofs::plonk::Expression; diff --git a/zkevm-circuits/src/state_circuit/test.rs b/zkevm-circuits/src/state_circuit/test.rs index 91eb8cc174..5e9c566ad5 100644 --- a/zkevm-circuits/src/state_circuit/test.rs +++ b/zkevm-circuits/src/state_circuit/test.rs @@ -1,7 +1,6 @@ use super::{StateCircuit, StateConfig}; -use crate::{evm_circuit::{ - witness::{Rw, RwMap}, -}, +use crate::{ + evm_circuit::witness::{Rw, RwMap}, table::{AccountFieldTag, CallContextFieldTag, RwTableTag, TxLogFieldTag, TxReceiptFieldTag}, }; use bus_mapping::operation::{ diff --git a/zkevm-circuits/src/table.rs b/zkevm-circuits/src/table.rs index 032c74d38b..a1bd883ec2 100644 --- a/zkevm-circuits/src/table.rs +++ b/zkevm-circuits/src/table.rs @@ -1,11 +1,10 @@ //! Table definitions used cross-circuits -use crate::evm_circuit::{witness::RwRow}; +use crate::evm_circuit::witness::RwRow; use crate::evm_circuit::{ util::{rlc, RandomLinearCombination}, witness::{BlockContext, Bytecode, RwMap, Transaction}, }; -use itertools::Itertools; use crate::impl_expr; use eth_types::{Field, ToLittleEndian, Word}; use halo2_proofs::{ @@ -14,6 +13,7 @@ use halo2_proofs::{ plonk::{Advice, Column, ConstraintSystem, Error}, }; use halo2_proofs::{circuit::Layouter, plonk::*}; +use itertools::Itertools; use keccak256::plain::Keccak; use strum_macros::{EnumCount, EnumIter}; @@ -54,7 +54,7 @@ pub enum TxFieldTag { CallData, } impl_expr!(TxFieldTag); -pub type TxContextFieldTag = TxFieldTag; +pub type TxContextFieldTag = TxFieldTag; /// TxTable columns #[derive(Clone, Debug)] diff --git a/zkevm-circuits/src/tx_circuit/sign_verify.rs b/zkevm-circuits/src/tx_circuit/sign_verify.rs index 7ee93182c9..13fe88c81b 100644 --- a/zkevm-circuits/src/tx_circuit/sign_verify.rs +++ b/zkevm-circuits/src/tx_circuit/sign_verify.rs @@ -5,10 +5,8 @@ // - *_le: Little-Endian bytes use crate::{ - evm_circuit::{ - util::{not, RandomLinearCombination, Word}, - }, - table::{load_keccaks, KeccakTable}, + evm_circuit::util::{not, RandomLinearCombination, Word}, + table::{load_keccaks, KeccakTable}, util::Expr, }; use ecc::{EccConfig, GeneralEccChip}; From 194c266900b4b2b6ff5678a48a5cb72d766f2a08 Mon Sep 17 00:00:00 2001 From: Eduard S Date: Mon, 18 Jul 2022 17:44:04 +0200 Subject: [PATCH 18/26] Document pub stuff --- .../src/bytecode_circuit/bytecode_unroller.rs | 4 +- zkevm-circuits/src/lib.rs | 1 - zkevm-circuits/src/rw_table.rs | 1 - zkevm-circuits/src/table.rs | 130 ++++++++++++++++-- zkevm-circuits/src/tx_circuit/sign_verify.rs | 4 +- 5 files changed, 124 insertions(+), 16 deletions(-) delete mode 100644 zkevm-circuits/src/rw_table.rs diff --git a/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs b/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs index fe9f1dab34..0de7919e58 100644 --- a/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs +++ b/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs @@ -2,8 +2,8 @@ use crate::{ evm_circuit::util::{ and, constraint_builder::BaseConstraintBuilder, not, or, select, RandomLinearCombination, }, - table::{load_keccaks, BytecodeTable, KeccakTable}, table::{BytecodeFieldTag, TableColumns}, + table::{BytecodeTable, KeccakTable}, util::Expr, }; use bus_mapping::evm::OpcodeId; @@ -717,7 +717,7 @@ fn into_words(message: &[u8]) -> Vec { #[cfg(test)] mod tests { use super::*; - use crate::util::power_of_randomness_from_instance; + use crate::{table::load_keccaks, util::power_of_randomness_from_instance}; use eth_types::{Bytecode, Word}; use halo2_proofs::{ circuit::{Layouter, SimpleFloorPlanner}, diff --git a/zkevm-circuits/src/lib.rs b/zkevm-circuits/src/lib.rs index 595a1a20db..c6a07b80b6 100644 --- a/zkevm-circuits/src/lib.rs +++ b/zkevm-circuits/src/lib.rs @@ -18,7 +18,6 @@ pub mod bytecode_circuit; pub mod evm_circuit; -pub mod rw_table; pub mod state_circuit; pub mod super_circuit; pub mod table; diff --git a/zkevm-circuits/src/rw_table.rs b/zkevm-circuits/src/rw_table.rs deleted file mode 100644 index 8b13789179..0000000000 --- a/zkevm-circuits/src/rw_table.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/zkevm-circuits/src/table.rs b/zkevm-circuits/src/table.rs index a1bd883ec2..0de9971588 100644 --- a/zkevm-circuits/src/table.rs +++ b/zkevm-circuits/src/table.rs @@ -17,12 +17,13 @@ use itertools::Itertools; use keccak256::plain::Keccak; use strum_macros::{EnumCount, EnumIter}; +/// Trait used for dynamic tables. pub trait TableColumns { + /// Returns the list of columns following the table order. This trait + /// requires all the columns to be of the same type. fn columns(&self) -> Vec>; } -// TODO: Deduplicate with -// `zkevm-circuits/src/evm_circuit/table.rs::TxContextFieldTag`. /// Tag used to identify each field in the transaction in a row of the /// transaction table. #[derive(Clone, Copy, Debug)] @@ -54,18 +55,25 @@ pub enum TxFieldTag { CallData, } impl_expr!(TxFieldTag); + +/// Alias for TxFieldTag used by EVM Circuit pub type TxContextFieldTag = TxFieldTag; -/// TxTable columns +/// Table that contains the fields of all Transactions in a block #[derive(Clone, Debug)] pub struct TxTable { + /// Tx ID pub tx_id: Column, + /// Tag (TxContextFieldTag) pub tag: Column, + /// Index for Tag = CallData pub index: Column, + /// Value pub value: Column, } impl TxTable { + /// Construct a new TxTable pub fn construct(meta: &mut ConstraintSystem) -> Self { Self { tx_id: meta.advice_column(), @@ -82,7 +90,8 @@ impl TableColumns for TxTable { } } -// TODO: Move to src/tables.rs +/// Assign the `TxTable` from a list of block `Transaction`s, followig the same +/// layout that the Tx Circuit uses. pub fn load_txs( tx_table: &TxTable, layouter: &mut impl Layouter, @@ -126,24 +135,38 @@ pub fn load_txs( ) } +/// Tag to identify the operation type in a RwTable row #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, EnumIter)] pub enum RwTableTag { + /// Start (used for padding) Start = 1, + /// Stack operation Stack, + /// Memory operation Memory, + /// Account Storage operation AccountStorage, + /// Tx Access List Account operation TxAccessListAccount, + /// Tx Access List Account Storage operation TxAccessListAccountStorage, + /// Tx Refund operation TxRefund, + /// Account operation Account, + /// Account Destructed operation AccountDestructed, + /// Call Context operation CallContext, + /// Tx Log operation TxLog, + /// Tx Receipt operation TxReceipt, } impl_expr!(RwTableTag); impl RwTableTag { + /// Returns true if the RwTable operation is reversible pub fn is_reversible(self) -> bool { return matches!( self, @@ -163,75 +186,125 @@ impl From for usize { } } +/// Tag for an AccountField in RwTable #[derive(Clone, Copy, Debug, EnumIter)] pub enum AccountFieldTag { + /// Nonce field Nonce = 1, + /// Balance field Balance, + /// CodeHash field CodeHash, } impl_expr!(AccountFieldTag); +/// Tag for a TxLogField in RwTable #[derive(Clone, Copy, Debug, PartialEq, EnumIter)] pub enum TxLogFieldTag { + /// Address field Address = 1, + /// Topic field Topic, + /// Data field Data, } impl_expr!(TxLogFieldTag); +/// Tag for a TxReceiptField in RwTable #[derive(Clone, Copy, Debug, PartialEq, EnumIter, EnumCount)] pub enum TxReceiptFieldTag { + /// Tx result PostStateOrStatus = 1, + /// CumulativeGasUsed in the tx CumulativeGasUsed, + /// Number of logs in the tx LogLength, } impl_expr!(TxReceiptFieldTag); +/// Tag for a CallContextField in RwTable #[derive(Clone, Copy, Debug, PartialEq, EnumIter)] pub enum CallContextFieldTag { + /// RwCounterEndOfReversion RwCounterEndOfReversion = 1, + /// CallerId CallerId, + /// TxId TxId, + /// Depth Depth, + /// CallerAddress CallerAddress, + /// CalleeAddress CalleeAddress, + /// CallDataOffset CallDataOffset, + /// CallDataLength CallDataLength, + /// ReturnDataOffset ReturnDataOffset, + /// ReturnDataLength ReturnDataLength, + /// Value Value, + /// IsSuccess IsSuccess, + /// IsPersistent IsPersistent, + /// IsStatic IsStatic, + /// LastCalleeId LastCalleeId, + /// LastCalleeReturnDataOffset LastCalleeReturnDataOffset, + /// LastCalleeReturnDataLength LastCalleeReturnDataLength, + /// IsRoot IsRoot, + /// IsCreate IsCreate, + /// CodeHash CodeHash, + /// ProgramCounter ProgramCounter, + /// StackPointer StackPointer, + /// GasLeft GasLeft, + /// MemorySize MemorySize, + /// ReversibleWriteCounter ReversibleWriteCounter, } impl_expr!(CallContextFieldTag); -/// The rw table shared between evm circuit and state circuit +/// The RwTable shared between EVM Circuit and State Circuit, which contains +/// traces of the EVM state operations. #[derive(Clone, Copy)] pub struct RwTable { + /// Read Write Counter pub rw_counter: Column, + /// Is Write pub is_write: Column, + /// Tag pub tag: Column, + /// Key1 (Id) pub key1: Column, + /// Key2 (Address) pub key2: Column, + /// Key3 (FieldTag) pub key3: Column, + /// Key3 (StorageKey) pub key4: Column, + /// Value pub value: Column, + /// Value Previous pub value_prev: Column, + /// Aux1 (Committed Value) pub aux1: Column, + /// Aux2 pub aux2: Column, } @@ -253,6 +326,7 @@ impl TableColumns for RwTable { } } impl RwTable { + /// Construct a new RwTable pub fn construct(meta: &mut ConstraintSystem) -> Self { Self { rw_counter: meta.advice_column(), @@ -268,6 +342,7 @@ impl RwTable { aux2: meta.advice_column(), } } + /// Assign a `RwRow` at offset into the `RwTable` pub fn assign( &self, region: &mut Region<'_, F>, @@ -293,7 +368,8 @@ impl RwTable { } } -// TODO: Move to src/tables.rs +/// Assign the `RwTable` from a `RwMap`, followig the same +/// table layout that the State Circuit uses. pub fn load_rws( rw_table: &RwTable, layouter: &mut impl Layouter, @@ -327,26 +403,37 @@ pub fn load_rws( ) } +/// Tag to identify the field in a Bytecode Table row #[derive(Clone, Copy, Debug)] pub enum BytecodeFieldTag { + /// Length field Length, + /// Byte field Byte, + /// Padding field Padding, } impl_expr!(BytecodeFieldTag); // CHANGELOG: Added BytecodeTable to help reusing the table config with other // circuits +/// Table with Bytecode indexed by its Code Hash #[derive(Clone, Debug)] pub struct BytecodeTable { + /// Code Hash pub code_hash: Column, // CHANGELOG: Renamed from hash + /// Tag pub tag: Column, + /// Index pub index: Column, + /// Is Code is true when the byte is not an argument to a PUSH* instruction. pub is_code: Column, + /// Value pub value: Column, } impl BytecodeTable { + /// Construct a new BytecodeTable pub fn construct(meta: &mut ConstraintSystem) -> Self { Self { code_hash: meta.advice_column(), @@ -372,7 +459,8 @@ impl TableColumns for BytecodeTable { // use crate::util::TableShow; -// TODO: Move to src/tables.rs +/// Assign the `BytecodeTable` from a list of bytecodes, followig the same +/// table layout that the Bytecode Circuit uses. pub fn load_bytecodes<'a, F: Field>( bytecode_table: &BytecodeTable, layouter: &mut impl Layouter, @@ -419,29 +507,43 @@ pub fn load_bytecodes<'a, F: Field>( ) } +/// Tag to identify the field in a Block Table row // Keep the sequence consistent with OpcodeId for scalar #[derive(Clone, Copy, Debug)] pub enum BlockContextFieldTag { + /// Coinbase field Coinbase = 1, + /// Timestamp field Timestamp, + /// Number field Number, + /// Difficulty field Difficulty, + /// Gas Limit field GasLimit, + /// Base Fee field BaseFee = 8, + /// Block Hash field BlockHash, + /// Chain ID field. Although this is not a field in the block header, we + /// add it here for convenience. ChainId, } impl_expr!(BlockContextFieldTag); -// TODO: Move to src/tables.rs +/// Table with Block header fields #[derive(Clone, Debug)] pub struct BlockTable { + /// Tag pub tag: Column, + /// Index pub index: Column, + /// Value pub value: Column, } impl BlockTable { + /// Construct a new BlockTable pub fn construct(meta: &mut ConstraintSystem) -> Self { Self { tag: meta.advice_column(), @@ -457,7 +559,7 @@ impl TableColumns for BlockTable { } } -// TODO: Move to src/tables.rs +/// Assign the `BlockTable` from a `BlockContext`. pub fn load_block( block_table: &BlockTable, layouter: &mut impl Layouter, @@ -496,16 +598,21 @@ pub fn load_block( ) } -// TODO: Move to src/tables.rs +/// Keccak Table, used to verify keccak hashing from RLC'ed input. #[derive(Clone, Debug)] pub struct KeccakTable { + /// True when the row is enabled pub is_enabled: Column, + /// Byte array input as `RLC(reversed(input))` pub input_rlc: Column, // RLC of input bytes + /// Byte array input length pub input_len: Column, + /// RLC of the hash result pub output_rlc: Column, // RLC of hash of input bytes } impl KeccakTable { + /// Construct a new KeccakTable pub fn construct(meta: &mut ConstraintSystem) -> Self { Self { is_enabled: meta.advice_column(), @@ -527,6 +634,7 @@ impl TableColumns for KeccakTable { } } +/// Generate the keccak table assignments from a byte array input. pub fn keccak_table_assignments(input: &[u8], randomness: F) -> Vec<[F; 4]> { // CHANGELOG: Using `RLC(reversed(input))` let input_rlc: F = rlc::value(input.iter().rev(), randomness); @@ -546,6 +654,8 @@ pub fn keccak_table_assignments(input: &[u8], randomness: F) -> Vec<[F // `RLC(reversed(input))` for convenience of the circuits that do the lookups. // This allows calculating the `input_rlc` after all the inputs bytes have been // layed out via the pattern `acc[i] = acc[i-1] * r + value[i]`. +/// Assign the `KeccakTable` from a list hashing inputs, followig the same +/// table layout that the Keccak Circuit uses. pub fn load_keccaks<'a, F: Field>( keccak_table: &KeccakTable, layouter: &mut impl Layouter, diff --git a/zkevm-circuits/src/tx_circuit/sign_verify.rs b/zkevm-circuits/src/tx_circuit/sign_verify.rs index 13fe88c81b..65d417599e 100644 --- a/zkevm-circuits/src/tx_circuit/sign_verify.rs +++ b/zkevm-circuits/src/tx_circuit/sign_verify.rs @@ -6,7 +6,7 @@ use crate::{ evm_circuit::util::{not, RandomLinearCombination, Word}, - table::{load_keccaks, KeccakTable}, + table::KeccakTable, util::Expr, }; use ecc::{EccConfig, GeneralEccChip}; @@ -833,7 +833,7 @@ fn pub_key_hash_to_address(pk_hash: &[u8]) -> F { #[cfg(test)] mod sign_verify_tests { use super::*; - use crate::util::power_of_randomness_from_instance; + use crate::{table::load_keccaks, util::power_of_randomness_from_instance}; use group::Group; use halo2_proofs::{ circuit::SimpleFloorPlanner, dev::MockProver, pairing::bn256::Fr, plonk::Circuit, From d6ff781a99eed0e69af0f0216fdd7f3f2c5bbf91 Mon Sep 17 00:00:00 2001 From: Eduard S Date: Mon, 18 Jul 2022 18:09:14 +0200 Subject: [PATCH 19/26] Fix merge --- Cargo.lock | 1 + Cargo.toml | 6 +- zkevm-circuits/src/copy_circuit.rs | 159 +++++----------------------- zkevm-circuits/src/evm_circuit.rs | 18 +--- zkevm-circuits/src/state_circuit.rs | 1 - zkevm-circuits/src/super_circuit.rs | 4 + zkevm-circuits/src/table.rs | 3 + 7 files changed, 43 insertions(+), 149 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f0d9ee6763..6ced703fef 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1854,6 +1854,7 @@ checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" [[package]] name = "halo2_proofs" version = "0.1.0-beta.1" +source = "git+https://github.com/ed255/halo2.git?branch=feature/dev-tooling#47834696cc62fb4c259c255d713e596b1e24f283" dependencies = [ "blake2b_simd 1.0.0", "bumpalo", diff --git a/Cargo.toml b/Cargo.toml index 7a75a713cd..c9134da0a7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,11 +20,13 @@ members = [ # is resolved: https://github.com/bitvecto-rs/bitvec/pull/141 bitvec = { git = "https://github.com/ed255/bitvec.git", rev = "5cfc5fa8496c66872d21905e677120fc3e79693c" } # halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", tag = "v2022_06_03" } -halo2_proofs = { path = "../halo2/halo2_proofs" } +# halo2_proofs = { path = "../halo2/halo2_proofs" } +halo2_proofs = { git = "https://github.com/ed255/halo2.git", branch = "feature/dev-tooling" } [patch."https://github.com/privacy-scaling-explorations/halo2"] # halo2_proofs = { git = "https://github.com/han0110/halo2", branch = "feature/abstraction-experiment", package = "halo2_proofs" } -halo2_proofs = { path = "../halo2/halo2_proofs" } +# halo2_proofs = { path = "../halo2/halo2_proofs" } +halo2_proofs = { git = "https://github.com/ed255/halo2.git", branch = "feature/dev-tooling" } # Definition of benchmarks profile to use. [profile.bench] diff --git a/zkevm-circuits/src/copy_circuit.rs b/zkevm-circuits/src/copy_circuit.rs index ffa10bb130..fcc3cc524e 100644 --- a/zkevm-circuits/src/copy_circuit.rs +++ b/zkevm-circuits/src/copy_circuit.rs @@ -15,10 +15,13 @@ use halo2_proofs::{ poly::Rotation, }; -use crate::evm_circuit::{ - table::{BytecodeFieldTag, LookupTable, RwTableTag, TxContextFieldTag, TxLogFieldTag}, - util::{constraint_builder::BaseConstraintBuilder, RandomLinearCombination}, - witness::Block, +use crate::{ + evm_circuit::{ + table::LookupTable, + util::{constraint_builder::BaseConstraintBuilder, RandomLinearCombination}, + witness::Block, + }, + table::{BytecodeFieldTag, RwTableTag, TxContextFieldTag, TxLogFieldTag}, }; /// The rw table shared between evm circuit and state circuit @@ -633,143 +636,26 @@ mod tests { use halo2_proofs::{ circuit::{Layouter, SimpleFloorPlanner}, dev::{MockProver, VerifyFailure}, - plonk::{Advice, Circuit, Column, ConstraintSystem, Error}, + plonk::{Circuit, ConstraintSystem}, }; - use itertools::Itertools; use mock::TestContext; use rand::{prelude::SliceRandom, Rng}; use crate::{ - evm_circuit::witness::{block_convert, Block, Bytecode, RwMap, Transaction}, - rw_table::RwTable, + evm_circuit::witness::{block_convert, Block}, + table::{load_bytecodes, load_rws, load_txs, BytecodeTable, RwTable, TxTable}, }; use super::CopyCircuit; #[derive(Clone)] struct MyConfig { - tx_table: [Column; 4], + tx_table: TxTable, rw_table: RwTable, - bytecode_table: [Column; 5], + bytecode_table: BytecodeTable, copy_table: CopyCircuit, } - impl MyConfig { - fn load_txs( - &self, - layouter: &mut impl Layouter, - txs: &[Transaction], - randomness: F, - ) -> Result<(), Error> { - layouter.assign_region( - || "tx table", - |mut region| { - let mut offset = 0; - for column in self.tx_table { - region.assign_advice( - || "tx table all-zero row", - column, - offset, - || Ok(F::zero()), - )?; - } - offset += 1; - - for tx in txs.iter() { - for row in tx.table_assignments(randomness) { - for (column, value) in self.tx_table.iter().zip_eq(row) { - region.assign_advice( - || format!("tx table row {}", offset), - *column, - offset, - || Ok(value), - )?; - } - offset += 1; - } - } - Ok(()) - }, - ) - } - - fn load_rws( - &self, - layouter: &mut impl Layouter, - rws: &RwMap, - randomness: F, - ) -> Result<(), Error> { - layouter.assign_region( - || "rw table", - |mut region| { - let mut offset = 0; - self.rw_table - .assign(&mut region, offset, &Default::default())?; - offset += 1; - - let mut rows = rws - .0 - .values() - .flat_map(|rws| rws.iter()) - .collect::>(); - - rows.sort_by_key(|a| a.rw_counter()); - let mut expected_rw_counter = 1; - for rw in rows { - assert!(rw.rw_counter() == expected_rw_counter); - expected_rw_counter += 1; - - self.rw_table.assign( - &mut region, - offset, - &rw.table_assignment(randomness), - )?; - offset += 1; - } - Ok(()) - }, - ) - } - - fn load_bytecodes<'a>( - &self, - layouter: &mut impl Layouter, - bytecodes: impl IntoIterator + Clone, - randomness: F, - ) -> Result<(), Error> { - layouter.assign_region( - || "bytecode table", - |mut region| { - let mut offset = 0; - for column in self.bytecode_table { - region.assign_advice( - || "bytecode table all-zero row", - column, - offset, - || Ok(F::zero()), - )?; - } - offset += 1; - - for bytecode in bytecodes.clone() { - for row in bytecode.table_assignments(randomness) { - for (column, value) in self.bytecode_table.iter().zip_eq(row) { - region.assign_advice( - || format!("bytecode table row {}", offset), - *column, - offset, - || Ok(value), - )?; - } - offset += 1; - } - } - Ok(()) - }, - ) - } - } - #[derive(Default)] struct MyCircuit { block: Block, @@ -790,9 +676,9 @@ mod tests { } fn configure(meta: &mut ConstraintSystem) -> Self::Config { - let tx_table = [(); 4].map(|_| meta.advice_column()); + let tx_table = TxTable::construct(meta); let rw_table = RwTable::construct(meta); - let bytecode_table = [(); 5].map(|_| meta.advice_column()); + let bytecode_table = BytecodeTable::construct(meta); let copy_table = CopyCircuit::configure(meta, &tx_table, &rw_table, &bytecode_table); MyConfig { @@ -808,9 +694,20 @@ mod tests { config: Self::Config, mut layouter: impl Layouter, ) -> Result<(), halo2_proofs::plonk::Error> { - config.load_txs(&mut layouter, &self.block.txs, self.block.randomness)?; - config.load_rws(&mut layouter, &self.block.rws, self.block.randomness)?; - config.load_bytecodes( + load_txs( + &config.tx_table, + &mut layouter, + &self.block.txs, + self.block.randomness, + )?; + load_rws( + &config.rw_table, + &mut layouter, + &self.block.rws, + self.block.randomness, + )?; + load_bytecodes( + &config.bytecode_table, &mut layouter, self.block.bytecodes.values(), self.block.randomness, diff --git a/zkevm-circuits/src/evm_circuit.rs b/zkevm-circuits/src/evm_circuit.rs index 7466c3da2b..5df2f7bed9 100644 --- a/zkevm-circuits/src/evm_circuit.rs +++ b/zkevm-circuits/src/evm_circuit.rs @@ -149,13 +149,8 @@ pub mod test { use crate::{ copy_circuit::CopyCircuit, evm_circuit::{table::FixedTableTag, witness::Block, EvmCircuit}, - evm_circuit::{ - table::FixedTableTag, - witness::{Block, BlockContext, Bytecode, RwMap, Transaction}, - EvmCircuit, - }, table::{load_block, load_bytecodes, load_rws, load_txs, BlockTable, RwTable}, - util::{power_of_randomness_from_instance, Expr}, + util::power_of_randomness_from_instance, }; use eth_types::{Field, Word}; use halo2_proofs::{ @@ -237,6 +232,7 @@ pub mod test { &rw_table, &bytecode_table, &block_table, + ©_table, ); Self::Config { @@ -245,15 +241,7 @@ pub mod test { bytecode_table, block_table, copy_table, - evm_circuit: EvmCircuit::configure( - meta, - power_of_randomness, - &tx_table, - &rw_table, - &bytecode_table, - &block_table, - ©_table, - ), + evm_circuit, } } diff --git a/zkevm-circuits/src/state_circuit.rs b/zkevm-circuits/src/state_circuit.rs index b11b137235..5f9109e8b5 100644 --- a/zkevm-circuits/src/state_circuit.rs +++ b/zkevm-circuits/src/state_circuit.rs @@ -7,7 +7,6 @@ mod random_linear_combination; #[cfg(test)] mod test; -use crate::util::Expr; use crate::{ evm_circuit::{ param::N_BYTES_WORD, diff --git a/zkevm-circuits/src/super_circuit.rs b/zkevm-circuits/src/super_circuit.rs index e9f60b4a88..01a5d622af 100644 --- a/zkevm-circuits/src/super_circuit.rs +++ b/zkevm-circuits/src/super_circuit.rs @@ -12,6 +12,7 @@ #![allow(missing_docs)] // use halo2_proofs::plonk::*; +use crate::copy_circuit::CopyCircuit; use crate::tx_circuit::{self, TxCircuit, TxCircuitConfig}; use crate::bytecode_circuit::bytecode_unroller::{ @@ -121,6 +122,8 @@ impl Circuit let bytecode_table = BytecodeTable::construct(meta); let block_table = BlockTable::construct(meta); let keccak_table = KeccakTable::construct(meta); + // TODO: Split CopyCircuit into a Table and the configuration. + let copy_table = CopyCircuit::configure(meta, &tx_table, &rw_table, &bytecode_table); let power_of_randomness = power_of_randomness_from_instance(meta); let evm_circuit = EvmCircuit::configure( @@ -135,6 +138,7 @@ impl Circuit &rw_table, &bytecode_table, &block_table, + ©_table, ); Self::Config { diff --git a/zkevm-circuits/src/table.rs b/zkevm-circuits/src/table.rs index 0de9971588..b5e5bd70cb 100644 --- a/zkevm-circuits/src/table.rs +++ b/zkevm-circuits/src/table.rs @@ -1,5 +1,8 @@ //! Table definitions used cross-circuits +// CHANGELOG: Move table definitions from evm_circuit/table.rs and rw_table.rs +// to here + use crate::evm_circuit::witness::RwRow; use crate::evm_circuit::{ util::{rlc, RandomLinearCombination}, From 06a9ea5f92bf819f9271d0890aac1643f8a52382 Mon Sep 17 00:00:00 2001 From: Eduard S Date: Tue, 19 Jul 2022 11:16:24 +0200 Subject: [PATCH 20/26] Pass clippy --- .../src/circuit_input_builder/execution.rs | 2 +- circuit-benchmarks/src/evm_circuit.rs | 9 +- .../src/bytecode_circuit/bytecode_unroller.rs | 5 +- zkevm-circuits/src/evm_circuit/table.rs | 6 +- zkevm-circuits/src/super_circuit.rs | 122 ++++++++---------- zkevm-circuits/src/util.rs | 10 +- 6 files changed, 73 insertions(+), 81 deletions(-) diff --git a/bus-mapping/src/circuit_input_builder/execution.rs b/bus-mapping/src/circuit_input_builder/execution.rs index 4ac95bd9b5..1b34004d1c 100644 --- a/bus-mapping/src/circuit_input_builder/execution.rs +++ b/bus-mapping/src/circuit_input_builder/execution.rs @@ -6,7 +6,7 @@ use eth_types::{ GethExecStep, H256, }; use gadgets::impl_expr; -use halo2_proofs::{arithmetic::FieldExt, plonk::Expression}; +use halo2_proofs::plonk::Expression; use strum_macros::EnumIter; /// An execution step of the EVM. diff --git a/circuit-benchmarks/src/evm_circuit.rs b/circuit-benchmarks/src/evm_circuit.rs index 9fb695fc2e..36bcd17b7b 100644 --- a/circuit-benchmarks/src/evm_circuit.rs +++ b/circuit-benchmarks/src/evm_circuit.rs @@ -6,6 +6,7 @@ use halo2_proofs::{ plonk::{Circuit, ConstraintSystem, Error, Expression}, }; use zkevm_circuits::evm_circuit::{witness::Block, EvmCircuit}; +use zkevm_circuits::table::{BlockTable, BytecodeTable, RwTable, TxTable}; #[derive(Debug, Default)] pub struct TestCircuit { @@ -21,10 +22,10 @@ impl Circuit for TestCircuit { } fn configure(meta: &mut ConstraintSystem) -> Self::Config { - let tx_table = [(); 4].map(|_| meta.advice_column()); - let rw_table = [(); 11].map(|_| meta.advice_column()); - let bytecode_table = [(); 5].map(|_| meta.advice_column()); - let block_table = [(); 3].map(|_| meta.advice_column()); + let tx_table = TxTable::construct(meta); + let rw_table = RwTable::construct(meta); + let bytecode_table = BytecodeTable::construct(meta); + let block_table = BlockTable::construct(meta); let copy_table = [(); 11].map(|_| meta.advice_column()); // Use constant expression to mock constant instance column for a more // reasonable benchmark. diff --git a/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs b/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs index 2a1cd132bf..192e996950 100644 --- a/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs +++ b/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs @@ -353,12 +353,11 @@ impl Config { not::expr(meta.query_advice(padding, Rotation::cur())), ]); let lookup_columns = vec![hash_input_rlc, code_length, bytecode_table.code_hash]; - let mut constraints = vec![]; // CHANGELOG: Add is_enabled expression to the keccak lookup - constraints.push(( + let mut constraints = vec![( enable.clone(), meta.query_advice(keccak_table.is_enabled, Rotation::cur()), - )); + )]; for (i, column) in keccak_table.columns().iter().skip(1).enumerate() { constraints.push(( enable.clone() * meta.query_advice(lookup_columns[i], Rotation::cur()), diff --git a/zkevm-circuits/src/evm_circuit/table.rs b/zkevm-circuits/src/evm_circuit/table.rs index c4d3ae36b6..8c611d238b 100644 --- a/zkevm-circuits/src/evm_circuit/table.rs +++ b/zkevm-circuits/src/evm_circuit/table.rs @@ -4,7 +4,7 @@ use crate::table::TableColumns; pub use crate::table::TxContextFieldTag; use eth_types::Field; use halo2_proofs::{ - plonk::{Advice, Column, Expression, Fixed, VirtualCells}, + plonk::{Advice, Any, Column, Expression, VirtualCells}, poly::Rotation, }; use strum::IntoEnumIterator; @@ -23,10 +23,10 @@ impl> LookupTable for T { } } -impl LookupTable for [Column; W] { +impl> + Clone, const W: usize> LookupTable for [C; W] { fn table_exprs(&self, meta: &mut VirtualCells) -> Vec> { self.iter() - .map(|column| meta.query_fixed(*column, Rotation::cur())) + .map(|column| meta.query_any(column.clone(), Rotation::cur())) .collect() } } diff --git a/zkevm-circuits/src/super_circuit.rs b/zkevm-circuits/src/super_circuit.rs index 01a5d622af..4d8c7510ac 100644 --- a/zkevm-circuits/src/super_circuit.rs +++ b/zkevm-circuits/src/super_circuit.rs @@ -1,16 +1,52 @@ -//! Mario Kart: Super Circuit -//! ⠀⠀⠀⠀⠀⠀⠀⢀⣀⣀⡀⠀⠀⠀⠀⠀⠀⠀ -//! ⠀⠀⠀⠀⡠⣴⣮⣷⣶⡶⣾⣽⣶⢤⡀⠀⠀⠀ -//! ⠀⠀⢠⣾⣿⢧⣾⣿⣿⣧⣿⣿⣿⣷⡱⡄⠀⠀ -//! ⠀⣠⣿⣿⣯⣿⣿⣿⣿⡿⣼⣻⠿⠟⠛⠻⢦⡀ -//! ⡼⠁⢿⣟⣎⣿⣿⠿⠟⠃⠉⠀⠀⠀⠀⠀⠀⣷ -//! ⢳⡀⠀⠀⠀⠀⠀⠀⠀⣀⡠⡤⢲⣾⡏⢱⡠⠃ -//! ⠀⠉⠲⡲⠒⠒⡖⠚⠿⢿⠃⠡⡀⠉⢁⠞⠀⠀ -//! ⠀⠀⠀⠘⠳⢄⣘⢤⣀⠈⢂⣤⠴⠚⠁⠀⠀⠀ -//! ⠀⠀⠀⠀⠀⠀⠀⠉⠉⠉⠁⠀⠀⠀⠀⠀⠀⠀ - -#![allow(missing_docs)] -// use halo2_proofs::plonk::*; +//! The Super Circuit is a circuit that contains all the circuits of the +//! zkEVM in order to achieve two things: +//! - Check the correct integration between circuits via the shared lookup +//! tables, to verify that the table layouts match. +//! - Allow having a single circuit setup for which a proof can be generated +//! that would be verified under a single aggregation circuit for the first +//! milestone. +//! +//! The current implementation contains the following circuits: +//! +//! - [x] EVM Circuit +//! - [ ] State Circuit +//! - [x] Tx Circuit +//! - [x] Bytecode Circuit +//! - [ ] Copy Circuit +//! - [ ] Keccak Circuit +//! - [ ] MPT Circuit +//! - [ ] PublicInputs Circuit +//! +//! And the following shared tables, with the circuits that use them: +//! +//! - [ ] Copy Table +//! - [ ] Copy Circuit +//! - [ ] EVM Circuit +//! - [ ] Rw Table +//! - [ ] State Circuit +//! - [ ] EVM Circuit +//! - [ ] Copy Circuit +//! - [x] Tx Table +//! - [x] Tx Circuit +//! - [x] EVM Circuit +//! - [ ] Copy Circuit +//! - [ ] PublicInputs Circuit +//! - [x] Bytecode Table +//! - [x] Bytecode Circuit +//! - [x] EVM Circuit +//! - [ ] Copy Circuit +//! - [ ] Block Table +//! - [ ] EVM Circuit +//! - [ ] PublicInputs Circuit +//! - [ ] MPT Table +//! - [ ] MPT Circuit +//! - [ ] State Circuit +//! - [x] Keccak Table +//! - [ ] Keccak Circuit +//! - [ ] EVM Circuit +//! - [x] Bytecode Circuit +//! - [x] Tx Circuit +//! - [ ] MPT Circuit use crate::copy_circuit::CopyCircuit; use crate::tx_circuit::{self, TxCircuit, TxCircuitConfig}; @@ -27,51 +63,10 @@ use crate::util::power_of_randomness_from_instance; use eth_types::Field; use halo2_proofs::{ circuit::{Layouter, SimpleFloorPlanner}, - plonk::{Circuit, ConstraintSystem, Error, Expression}, + plonk::{Circuit, ConstraintSystem, Error}, }; -// The SuperCircuit contains the following circuits: -// -// - [x] EVM Circuit -// - [ ] State Circuit -// - [x] Tx Circuit -// - [x] Bytecode Circuit -// - [ ] Copy Circuit -// - [ ] Keccak Circuit -// - [ ] MPT Circuit -// - [ ] PublicInputs Circuit -// -// And the following shared tables, with the circuits that use them: -// -// - [ ] Copy Table -// - [ ] Copy Circuit -// - [ ] EVM Circuit -// - [ ] Rw Table -// - [ ] State Circuit -// - [ ] EVM Circuit -// - [ ] Copy Circuit -// - [x] Tx Table -// - [x] Tx Circuit -// - [x] EVM Circuit -// - [ ] Copy Circuit -// - [ ] PublicInputs Circuit -// - [x] Bytecode Table -// - [x] Bytecode Circuit -// - [x] EVM Circuit -// - [ ] Copy Circuit -// - [ ] Block Table -// - [ ] EVM Circuit -// - [ ] PublicInputs Circuit -// - [ ] MPT Table -// - [ ] MPT Circuit -// - [ ] State Circuit -// - [x] Keccak Table -// - [ ] Keccak Circuit -// - [ ] EVM Circuit -// - [x] Bytecode Circuit -// - [x] Tx Circuit -// - [ ] MPT Circuit - +/// Configuration of the Super Circuit #[derive(Clone)] pub struct SuperCircuitConfig { tx_table: TxTable, @@ -84,6 +79,7 @@ pub struct SuperCircuitConfig, } +/// The Super Circuit contains all the zkEVM circuits #[derive(Default)] pub struct SuperCircuit { // EVM Circuit @@ -99,6 +95,7 @@ pub struct SuperCircuit SuperCircuit { + /// Return the number of rows required to verify a given block pub fn get_num_rows_required(block: &Block) -> usize { let mut cs = ConstraintSystem::default(); let config = Self::configure(&mut cs); @@ -128,12 +125,7 @@ impl Circuit let power_of_randomness = power_of_randomness_from_instance(meta); let evm_circuit = EvmCircuit::configure( meta, - power_of_randomness[..31] - .iter() - .cloned() - .collect::>>() - .try_into() - .unwrap(), + power_of_randomness[..31].to_vec().try_into().unwrap(), &tx_table, &rw_table, &bytecode_table, @@ -224,7 +216,7 @@ impl Circuit self.block.context.chain_id.as_u64(), )?); // Lookups from BytecodeCircuit - for (_, bytecode) in &self.block.bytecodes { + for bytecode in self.block.bytecodes.values() { keccak_inputs.push(bytecode.bytes.clone()); } // Load Keccak Table @@ -380,7 +372,7 @@ mod super_circuit_tests { let addr_b = address!("0x000000000000000000000000000000000000BBBB"); let mut wallets = HashMap::new(); - wallets.insert(wallet_a.address(), wallet_a.clone()); + wallets.insert(wallet_a.address(), wallet_a); // Create a custom tx setting Gas to let mut block: GethData = TestContext::<2, 1>::new( @@ -408,7 +400,7 @@ mod super_circuit_tests { .eth_block .transactions .iter() - .map(|tx| geth_types::Transaction::from_eth_tx(tx)) + .map(geth_types::Transaction::from_eth_tx) .collect(); let mut builder = BlockData::new_from_geth_data(block.clone()).new_circuit_input_builder(); diff --git a/zkevm-circuits/src/util.rs b/zkevm-circuits/src/util.rs index 443fdeb55b..ab7ed4905f 100644 --- a/zkevm-circuits/src/util.rs +++ b/zkevm-circuits/src/util.rs @@ -58,20 +58,20 @@ impl TableShow { len }) .collect(); - for row in 0..self.columns[0].len() { + for row_index in 0..self.columns[0].len() { print!("|"); - for col in 0..self.columns.len() { + for (column_index, column) in self.columns.iter().enumerate() { print!( " {:02x} |", - self.columns[col][row] + column[row_index] .to_repr() .as_ref() .iter() - .take(num_bytes[col]) + .take(num_bytes[column_index]) .format("") ); } - println!(""); + println!(); } } } From a9beebb1ceec0f747d412c8612f212289761d22b Mon Sep 17 00:00:00 2001 From: Eduard S Date: Tue, 19 Jul 2022 12:20:50 +0200 Subject: [PATCH 21/26] WIP --- .../src/bytecode_circuit/bytecode_unroller.rs | 3 +- zkevm-circuits/src/copy_circuit.rs | 3 +- zkevm-circuits/src/evm_circuit.rs | 4 +- zkevm-circuits/src/evm_circuit/execution.rs | 3 +- zkevm-circuits/src/evm_circuit/table.rs | 41 +----- zkevm-circuits/src/table.rs | 131 ++++++++++++++++-- 6 files changed, 127 insertions(+), 58 deletions(-) diff --git a/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs b/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs index 192e996950..d214bae265 100644 --- a/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs +++ b/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs @@ -2,8 +2,7 @@ use crate::{ evm_circuit::util::{ and, constraint_builder::BaseConstraintBuilder, not, or, select, RandomLinearCombination, }, - table::{BytecodeFieldTag, TableColumns}, - table::{BytecodeTable, KeccakTable}, + table::{BytecodeFieldTag, BytecodeTable, KeccakTable, LookupTable}, util::Expr, }; use bus_mapping::evm::OpcodeId; diff --git a/zkevm-circuits/src/copy_circuit.rs b/zkevm-circuits/src/copy_circuit.rs index fcc3cc524e..baaa8043d3 100644 --- a/zkevm-circuits/src/copy_circuit.rs +++ b/zkevm-circuits/src/copy_circuit.rs @@ -17,11 +17,10 @@ use halo2_proofs::{ use crate::{ evm_circuit::{ - table::LookupTable, util::{constraint_builder::BaseConstraintBuilder, RandomLinearCombination}, witness::Block, }, - table::{BytecodeFieldTag, RwTableTag, TxContextFieldTag, TxLogFieldTag}, + table::{BytecodeFieldTag, LookupTable, RwTableTag, TxContextFieldTag, TxLogFieldTag}, }; /// The rw table shared between evm circuit and state circuit diff --git a/zkevm-circuits/src/evm_circuit.rs b/zkevm-circuits/src/evm_circuit.rs index 5df2f7bed9..0737ef2baf 100644 --- a/zkevm-circuits/src/evm_circuit.rs +++ b/zkevm-circuits/src/evm_circuit.rs @@ -11,11 +11,11 @@ pub(crate) mod util; pub mod table; pub mod witness; -use crate::table::{BytecodeTable, TxTable}; +use crate::table::{BytecodeTable, LookupTable, TxTable}; use eth_types::Field; use execution::ExecutionConfig; use itertools::Itertools; -use table::{FixedTableTag, LookupTable}; +use table::FixedTableTag; use witness::Block; /// EvmCircuit implements verification of execution trace of a block. diff --git a/zkevm-circuits/src/evm_circuit/execution.rs b/zkevm-circuits/src/evm_circuit/execution.rs index 35bf947ad0..46164186e0 100644 --- a/zkevm-circuits/src/evm_circuit/execution.rs +++ b/zkevm-circuits/src/evm_circuit/execution.rs @@ -3,13 +3,14 @@ use crate::{ evm_circuit::{ param::{MAX_STEP_HEIGHT, STEP_WIDTH}, step::{ExecutionState, Step}, - table::{LookupTable, Table}, + table::Table, util::{ constraint_builder::{BaseConstraintBuilder, ConstraintBuilder}, rlc, CellType, }, witness::{Block, Call, ExecStep, Transaction}, }, + table::LookupTable, util::Expr, }; use eth_types::Field; diff --git a/zkevm-circuits/src/evm_circuit/table.rs b/zkevm-circuits/src/evm_circuit/table.rs index 8c611d238b..0815cc466e 100644 --- a/zkevm-circuits/src/evm_circuit/table.rs +++ b/zkevm-circuits/src/evm_circuit/table.rs @@ -1,36 +1,11 @@ use crate::evm_circuit::step::ExecutionState; use crate::impl_expr; -use crate::table::TableColumns; pub use crate::table::TxContextFieldTag; use eth_types::Field; -use halo2_proofs::{ - plonk::{Advice, Any, Column, Expression, VirtualCells}, - poly::Rotation, -}; +use halo2_proofs::plonk::Expression; use strum::IntoEnumIterator; use strum_macros::EnumIter; -pub trait LookupTable { - fn table_exprs(&self, meta: &mut VirtualCells) -> Vec>; -} - -impl> LookupTable for T { - fn table_exprs(&self, meta: &mut VirtualCells) -> Vec> { - self.columns() - .iter() - .map(|column| meta.query_advice(*column, Rotation::cur())) - .collect() - } -} - -impl> + Clone, const W: usize> LookupTable for [C; W] { - fn table_exprs(&self, meta: &mut VirtualCells) -> Vec> { - self.iter() - .map(|column| meta.query_any(column.clone(), Rotation::cur())) - .collect() - } -} - #[derive(Clone, Copy, Debug, EnumIter)] pub enum FixedTableTag { Zero = 0, @@ -120,20 +95,6 @@ impl FixedTableTag { } } -// #[derive(Clone, Copy, Debug)] -// pub enum TxContextFieldTag { -// Nonce = 1, -// Gas, -// GasPrice, -// CallerAddress, -// CalleeAddress, -// IsCreate, -// Value, -// CallDataLength, -// CallDataGasCost, -// CallData, -// } - #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, EnumIter)] pub(crate) enum Table { Fixed, diff --git a/zkevm-circuits/src/table.rs b/zkevm-circuits/src/table.rs index b5e5bd70cb..8363e7093e 100644 --- a/zkevm-circuits/src/table.rs +++ b/zkevm-circuits/src/table.rs @@ -15,16 +15,49 @@ use halo2_proofs::{ circuit::Region, plonk::{Advice, Column, ConstraintSystem, Error}, }; -use halo2_proofs::{circuit::Layouter, plonk::*}; +use halo2_proofs::{circuit::Layouter, plonk::*, poly::Rotation}; use itertools::Itertools; use keccak256::plain::Keccak; use strum_macros::{EnumCount, EnumIter}; -/// Trait used for dynamic tables. -pub trait TableColumns { - /// Returns the list of columns following the table order. This trait - /// requires all the columns to be of the same type. - fn columns(&self) -> Vec>; +// /// Trait used for dynamic tables. +// pub trait TableColumns { +// /// Returns the list of columns following the table order. This trait +// /// requires all the columns to be of the same type. +// fn columns(&self) -> Vec>; +// } + +/// Trait used to define lookup tables +pub trait LookupTable { + /// Returns the list of advice columns following the table order. + fn columns(&self) -> Vec> { + Vec::new() + } + + /// Return the list of expressions used to define the lookup table. + fn table_exprs(&self, meta: &mut VirtualCells) -> Vec> { + self.columns() + .iter() + .map(|column| meta.query_advice(*column, Rotation::cur())) + .collect() + } +} + +// impl> LookupTable for T { +// fn table_exprs(&self, meta: &mut VirtualCells) -> Vec> { +// self.columns() +// .iter() +// .map(|column| meta.query_advice(*column, Rotation::cur())) +// .collect() +// } +// } + +impl> + Clone, const W: usize> LookupTable for [C; W] { + fn table_exprs(&self, meta: &mut VirtualCells) -> Vec> { + self.iter() + .map(|column| meta.query_any(column.clone(), Rotation::cur())) + .collect() + } } /// Tag used to identify each field in the transaction in a row of the @@ -87,7 +120,7 @@ impl TxTable { } } -impl TableColumns for TxTable { +impl LookupTable for TxTable { fn columns(&self) -> Vec> { vec![self.tx_id, self.tag, self.index, self.value] } @@ -311,7 +344,7 @@ pub struct RwTable { pub aux2: Column, } -impl TableColumns for RwTable { +impl LookupTable for RwTable { fn columns(&self) -> Vec> { vec![ self.rw_counter, @@ -448,7 +481,7 @@ impl BytecodeTable { } } -impl TableColumns for BytecodeTable { +impl LookupTable for BytecodeTable { fn columns(&self) -> Vec> { vec![ self.code_hash, @@ -556,7 +589,7 @@ impl BlockTable { } } -impl TableColumns for BlockTable { +impl LookupTable for BlockTable { fn columns(&self) -> Vec> { vec![self.tag, self.index, self.value] } @@ -626,7 +659,7 @@ impl KeccakTable { } } -impl TableColumns for KeccakTable { +impl LookupTable for KeccakTable { fn columns(&self) -> Vec> { vec![ self.is_enabled, @@ -705,3 +738,79 @@ pub fn load_keccaks<'a, F: Field>( }, ) } + +/// Copy Table, used to verify copies of byte chunks between Memory, Bytecode, +/// TxLogs and TxCallData. +#[derive(Clone, Debug)] +pub struct CopyTable { + /// Boolean value to indicate the first row in a copy event. + pub is_first: Column, + /// Can be $txID, $callID, $codeHash (RLC encoded). + pub id: Column, + /// Type of data source/destination, including Memory, Bytecode, TxCalldata, + /// TxLog. + pub tag: Column, + /// Address in the source data. Can be memory address, byte index in the + /// bytecode, tx call data, and tx log data. + pub addr: Column, + /// Address boundary of the source data. Any data read from address greater + /// than or equal to this value will be 0. + pub src_addr_end: Column, + /// Number of bytes to be copied. + pub bytes_left: Column, + /// Current RW counter at the beginning of the copy + pub rw_counter: Column, + /// How much the RW counter will increase in a copy event. + pub rwc_inc_left: Column, +} + +/* +impl CopyTable { + /// Construct a new KeccakTable + pub fn construct(meta: &mut ConstraintSystem) -> Self { + Self { + is_first: meta.advice_column(), + id: meta.advice_column(), + tag: meta.advice_column(), + addr: meta.advice_column(), + src_addr_end: meta.advice_column(), + bytes_left: meta.advice_column(), + rw_counter: meta.advice_column(), + rwc_inc_left: meta.advice_column(), + } + } +} + +impl TableColumns for CopyTable { + fn columns(&self) -> Vec> { + vec![ + self.is_first, + self.id, + self.tag, + self.addr, + self.src_addr_end, + self.bytes_left, + self.rw_counter, + self.rwc_inc_left, + ] + } +} + +impl LookupTable for CopyTable { + fn table_exprs(&self, meta: &mut VirtualCells) -> Vec> { + vec![ + meta.query_advice(self.is_first, Rotation::cur()), + meta.query_advice(self.id, Rotation::cur()), // src_id + self.tag.value(Rotation::cur())(meta), // src_tag + meta.query_advice(self.id, Rotation::next()), // dst_id + self.tag.value(Rotation::next())(meta), // dst_tag + meta.query_advice(self.addr, Rotation::cur()), // src_addr + meta.query_advice(self.src_addr_end, Rotation::cur()), // src_addr_end + meta.query_advice(self.addr, Rotation::next()), // dst_addr + meta.query_advice(self.bytes_left, Rotation::cur()), // length + meta.query_advice(self.rw_counter, Rotation::cur()), // rw_counter + meta.query_advice(self.rwc_inc_left, Rotation::cur()), // rwc_inc_left + ] + } +} +*/ From 38f7e7ca01a4aa24d92de908988095ec95edbffc Mon Sep 17 00:00:00 2001 From: Eduard S Date: Tue, 19 Jul 2022 16:22:22 +0200 Subject: [PATCH 22/26] Abstract CopyTable from CopyCircuit --- .../src/bytecode_circuit/bytecode_unroller.rs | 2 +- zkevm-circuits/src/copy_circuit.rs | 162 +++++++--------- zkevm-circuits/src/evm_circuit.rs | 21 +- zkevm-circuits/src/super_circuit.rs | 18 +- zkevm-circuits/src/table.rs | 180 +++++++++++++----- 5 files changed, 226 insertions(+), 157 deletions(-) diff --git a/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs b/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs index d214bae265..5f88224d56 100644 --- a/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs +++ b/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs @@ -2,7 +2,7 @@ use crate::{ evm_circuit::util::{ and, constraint_builder::BaseConstraintBuilder, not, or, select, RandomLinearCombination, }, - table::{BytecodeFieldTag, BytecodeTable, KeccakTable, LookupTable}, + table::{BytecodeFieldTag, BytecodeTable, KeccakTable, TableColumns}, util::Expr, }; use bus_mapping::evm::OpcodeId; diff --git a/zkevm-circuits/src/copy_circuit.rs b/zkevm-circuits/src/copy_circuit.rs index baaa8043d3..83befc72dd 100644 --- a/zkevm-circuits/src/copy_circuit.rs +++ b/zkevm-circuits/src/copy_circuit.rs @@ -5,13 +5,13 @@ use bus_mapping::circuit_input_builder::{CopyDataType, CopyEvent, CopyStep, NumberOrHash}; use eth_types::{Field, ToAddress, ToScalar, U256}; use gadgets::{ - binary_number::{BinaryNumberChip, BinaryNumberConfig}, + binary_number::BinaryNumberChip, less_than::{LtChip, LtConfig, LtInstruction}, util::{and, not, or, Expr}, }; use halo2_proofs::{ circuit::{Layouter, Region}, - plonk::{Advice, Column, ConstraintSystem, Error, Expression, Fixed, Selector, VirtualCells}, + plonk::{Advice, Column, ConstraintSystem, Error, Fixed, Selector}, poly::Rotation, }; @@ -20,9 +20,29 @@ use crate::{ util::{constraint_builder::BaseConstraintBuilder, RandomLinearCombination}, witness::Block, }, - table::{BytecodeFieldTag, LookupTable, RwTableTag, TxContextFieldTag, TxLogFieldTag}, + table::{ + BytecodeFieldTag, CopyTable, LookupTable, RwTableTag, TxContextFieldTag, TxLogFieldTag, + }, }; +/// Encode the type `NumberOrHash` into a field element +pub fn number_or_hash_to_field(v: &NumberOrHash, randomness: F) -> F { + match v { + NumberOrHash::Number(n) => F::from(*n as u64), + NumberOrHash::Hash(h) => { + // since code hash in the bytecode table is represented in + // the little-endian form, we reverse the big-endian bytes + // of H256. + let le_bytes = { + let mut b = h.to_fixed_bytes(); + b.reverse(); + b + }; + RandomLinearCombination::random_linear_combine(le_bytes, randomness) + } + } +} + /// The rw table shared between evm circuit and state circuit #[derive(Clone, Copy, Debug)] pub struct CopyCircuit { @@ -31,22 +51,11 @@ pub struct CopyCircuit { /// Whether this row denotes a step. A read row is a step and a write row is /// not. pub q_step: Selector, - /// Whether the row is the first read-write pair for a copy event. - pub is_first: Column, /// Whether the row is the last read-write pair for a copy event. pub is_last: Column, - /// The relevant ID for the read-write row, represented as a random linear - /// combination. The ID may be one of the below: - /// 1. Call ID/Caller ID for CopyDataType::Memory - /// 2. RLC encoding of bytecode hash for CopyDataType::Bytecode - /// 3. Transaction ID for CopyDataType::TxCalldata, CopyDataType::TxLog - pub id: Column, - /// The source/destination address for this copy step. - pub addr: Column, - /// The end of the source buffer for the copy event. - pub src_addr_end: Column, - /// The number of bytes left to be copied. - pub bytes_left: Column, + /// The Copy Table contains the columns that are exposed via the lookup + /// expressions + pub copy_table: CopyTable, /// The value copied in this copy step. pub value: Column, /// In case of a bytecode tag, this denotes whether or not the copied byte @@ -54,38 +63,12 @@ pub struct CopyCircuit { pub is_code: Column, /// Whether the row is padding. pub is_pad: Column, - /// The associated read-write counter for this row. - pub rw_counter: Column, - /// Decrementing counter denoting reverse read-write counter. - pub rwc_inc_left: Column, - /// Binary chip to constrain the copy table conditionally depending on the - /// current row's tag, whether it is Bytecode, Memory, TxCalldata or - /// TxLog. - pub tag: BinaryNumberConfig, /// Lt chip to check: src_addr < src_addr_end. /// Since `src_addr` and `src_addr_end` are u64, 8 bytes are sufficient for /// the Lt chip. pub addr_lt_addr_end: LtConfig, } -impl LookupTable for CopyCircuit { - fn table_exprs(&self, meta: &mut VirtualCells) -> Vec> { - vec![ - meta.query_advice(self.is_first, Rotation::cur()), - meta.query_advice(self.id, Rotation::cur()), // src_id - self.tag.value(Rotation::cur())(meta), // src_tag - meta.query_advice(self.id, Rotation::next()), // dst_id - self.tag.value(Rotation::next())(meta), // dst_tag - meta.query_advice(self.addr, Rotation::cur()), // src_addr - meta.query_advice(self.src_addr_end, Rotation::cur()), // src_addr_end - meta.query_advice(self.addr, Rotation::next()), // dst_addr - meta.query_advice(self.bytes_left, Rotation::cur()), // length - meta.query_advice(self.rw_counter, Rotation::cur()), // rw_counter - meta.query_advice(self.rwc_inc_left, Rotation::cur()), // rwc_inc_left - ] - } -} - impl CopyCircuit { /// Configure the Copy Circuit constraining read-write steps and doing /// appropriate lookups to the Tx Table, RW Table and Bytecode Table. @@ -94,22 +77,22 @@ impl CopyCircuit { tx_table: &dyn LookupTable, rw_table: &dyn LookupTable, bytecode_table: &dyn LookupTable, + copy_table: CopyTable, + q_enable: Column, ) -> Self { - let q_enable = meta.fixed_column(); let q_step = meta.complex_selector(); - let is_first = meta.advice_column(); let is_last = meta.advice_column(); - let id = meta.advice_column(); - let addr = meta.advice_column(); - let src_addr_end = meta.advice_column(); - let bytes_left = meta.advice_column(); let value = meta.advice_column(); let is_code = meta.advice_column(); let is_pad = meta.advice_column(); - let rw_counter = meta.advice_column(); - let rwc_inc_left = meta.advice_column(); - - let tag = BinaryNumberChip::configure(meta, q_enable); + let is_first = copy_table.is_first; + let id = copy_table.id; + let addr = copy_table.addr; + let src_addr_end = copy_table.src_addr_end; + let bytes_left = copy_table.bytes_left; + let rw_counter = copy_table.rw_counter; + let rwc_inc_left = copy_table.rwc_inc_left; + let tag = copy_table.tag; let addr_lt_addr_end = LtChip::configure( meta, @@ -279,7 +262,8 @@ impl CopyCircuit { 1.expr(), RwTableTag::TxLog.expr(), meta.query_advice(id, Rotation::cur()), // tx_id - meta.query_advice(addr, Rotation::cur()), // byte_index || field_tag || log_id + meta.query_advice(addr, Rotation::cur()), /* byte_index || field_tag || + * log_id */ 0.expr(), 0.expr(), meta.query_advice(value, Rotation::cur()), @@ -329,19 +313,12 @@ impl CopyCircuit { Self { q_enable, q_step, - is_first, is_last, - id, - addr, - src_addr_end, - bytes_left, value, is_code, is_pad, - rw_counter, - rwc_inc_left, - tag, addr_lt_addr_end, + copy_table, } } @@ -351,7 +328,7 @@ impl CopyCircuit { layouter: &mut impl Layouter, block: &Block, ) -> Result<(), Error> { - let tag_chip = BinaryNumberChip::construct(self.tag); + let tag_chip = BinaryNumberChip::construct(self.copy_table.tag); let lt_chip = LtChip::construct(self.addr_lt_addr_end); layouter.assign_region( @@ -412,7 +389,7 @@ impl CopyCircuit { // is_first region.assign_advice( || format!("assign is_first {}", offset), - self.is_first, + self.copy_table.is_first, offset, || Ok(if step_idx == 0 { F::one() } else { F::zero() }), )?; @@ -432,29 +409,14 @@ impl CopyCircuit { // id region.assign_advice( || format!("assign id {}", offset), - self.id, + self.copy_table.id, offset, - || { - Ok(match id { - NumberOrHash::Number(n) => F::from(*n as u64), - NumberOrHash::Hash(h) => { - // since code hash in the bytecode table is represented in - // the little-endian form, we reverse the big-endian bytes - // of H256. - let le_bytes = { - let mut b = h.to_fixed_bytes(); - b.reverse(); - b - }; - RandomLinearCombination::random_linear_combine(le_bytes, randomness) - } - }) - }, + || Ok(number_or_hash_to_field(id, randomness)), )?; // addr region.assign_advice( || format!("assign addr {}", offset), - self.addr, + self.copy_table.addr, offset, || { Ok(match copy_step.tag { @@ -493,14 +455,14 @@ impl CopyCircuit { // rw_counter region.assign_advice( || format!("assign rw_counter {}", offset), - self.rw_counter, + self.copy_table.rw_counter, offset, || Ok(F::from(copy_step.rwc.0 as u64)), )?; // rwc_inc_left region.assign_advice( || format!("assign rwc_inc_left {}", offset), - self.rwc_inc_left, + self.copy_table.rwc_inc_left, offset, || Ok(F::from(copy_step.rwc_inc_left)), )?; @@ -511,14 +473,14 @@ impl CopyCircuit { // src_addr_end region.assign_advice( || format!("assign src_addr_end {}", offset), - self.src_addr_end, + self.copy_table.src_addr_end, offset, || Ok(F::from(copy_event.src_addr_end)), )?; // bytes_left region.assign_advice( || format!("assign bytes_left {}", offset), - self.bytes_left, + self.copy_table.bytes_left, offset, || Ok(F::from(bytes_left)), )?; @@ -544,7 +506,7 @@ impl CopyCircuit { // is_first region.assign_advice( || format!("assign is_first {}", offset), - self.is_first, + self.copy_table.is_first, offset, || Ok(F::zero()), )?; @@ -558,28 +520,28 @@ impl CopyCircuit { // id region.assign_advice( || format!("assign id {}", offset), - self.id, + self.copy_table.id, offset, || Ok(F::zero()), )?; // addr region.assign_advice( || format!("assign addr {}", offset), - self.addr, + self.copy_table.addr, offset, || Ok(F::zero()), )?; // src_addr_end region.assign_advice( || format!("assign src_addr_end {}", offset), - self.src_addr_end, + self.copy_table.src_addr_end, offset, || Ok(F::zero()), )?; // bytes_left region.assign_advice( || format!("assign bytes_left {}", offset), - self.bytes_left, + self.copy_table.bytes_left, offset, || Ok(F::zero()), )?; @@ -607,14 +569,14 @@ impl CopyCircuit { // rw_counter region.assign_advice( || format!("assign rw_counter {}", offset), - self.rw_counter, + self.copy_table.rw_counter, offset, || Ok(F::zero()), )?; // rwc_inc_left region.assign_advice( || format!("assign rwc_inc_left {}", offset), - self.rwc_inc_left, + self.copy_table.rwc_inc_left, offset, || Ok(F::zero()), )?; @@ -626,6 +588,7 @@ impl CopyCircuit { #[cfg(test)] mod tests { + use super::*; use bus_mapping::{ circuit_input_builder::{CircuitInputBuilder, CopyDataType}, mock::BlockData, @@ -645,8 +608,6 @@ mod tests { table::{load_bytecodes, load_rws, load_txs, BytecodeTable, RwTable, TxTable}, }; - use super::CopyCircuit; - #[derive(Clone)] struct MyConfig { tx_table: TxTable, @@ -678,7 +639,16 @@ mod tests { let tx_table = TxTable::construct(meta); let rw_table = RwTable::construct(meta); let bytecode_table = BytecodeTable::construct(meta); - let copy_table = CopyCircuit::configure(meta, &tx_table, &rw_table, &bytecode_table); + let q_enable = meta.fixed_column(); + let copy_table = CopyTable::construct(meta, q_enable); + let copy_table = CopyCircuit::configure( + meta, + &tx_table, + &rw_table, + &bytecode_table, + copy_table, + q_enable, + ); MyConfig { tx_table, diff --git a/zkevm-circuits/src/evm_circuit.rs b/zkevm-circuits/src/evm_circuit.rs index 0737ef2baf..106b659768 100644 --- a/zkevm-circuits/src/evm_circuit.rs +++ b/zkevm-circuits/src/evm_circuit.rs @@ -11,7 +11,7 @@ pub(crate) mod util; pub mod table; pub mod witness; -use crate::table::{BytecodeTable, LookupTable, TxTable}; +use crate::table::LookupTable; use eth_types::Field; use execution::ExecutionConfig; use itertools::Itertools; @@ -145,11 +145,12 @@ impl EvmCircuit { #[cfg(any(feature = "test", test))] pub mod test { - use super::*; use crate::{ - copy_circuit::CopyCircuit, evm_circuit::{table::FixedTableTag, witness::Block, EvmCircuit}, - table::{load_block, load_bytecodes, load_rws, load_txs, BlockTable, RwTable}, + table::{ + load_block, load_bytecodes, load_copy, load_rws, load_txs, BlockTable, BytecodeTable, + CopyTable, RwTable, TxTable, + }, util::power_of_randomness_from_instance, }; use eth_types::{Field, Word}; @@ -190,7 +191,7 @@ pub mod test { rw_table: RwTable, bytecode_table: BytecodeTable, block_table: BlockTable, - copy_table: CopyCircuit, + copy_table: CopyTable, evm_circuit: EvmCircuit, } @@ -222,7 +223,8 @@ pub mod test { let rw_table = RwTable::construct(meta); let bytecode_table = BytecodeTable::construct(meta); let block_table = BlockTable::construct(meta); - let copy_table = CopyCircuit::configure(meta, &tx_table, &rw_table, &bytecode_table); + let q_copy_table = meta.fixed_column(); + let copy_table = CopyTable::construct(meta, q_copy_table); let power_of_randomness = power_of_randomness_from_instance(meta); let evm_circuit = EvmCircuit::configure( @@ -278,7 +280,12 @@ pub mod test { &self.block.context, self.block.randomness, )?; - config.copy_table.assign_block(&mut layouter, &self.block)?; + load_copy( + &config.copy_table, + &mut layouter, + &self.block, + self.block.randomness, + )?; config .evm_circuit .assign_block_exact(&mut layouter, &self.block) diff --git a/zkevm-circuits/src/super_circuit.rs b/zkevm-circuits/src/super_circuit.rs index 4d8c7510ac..d41d45ee54 100644 --- a/zkevm-circuits/src/super_circuit.rs +++ b/zkevm-circuits/src/super_circuit.rs @@ -48,7 +48,6 @@ //! - [x] Tx Circuit //! - [ ] MPT Circuit -use crate::copy_circuit::CopyCircuit; use crate::tx_circuit::{self, TxCircuit, TxCircuitConfig}; use crate::bytecode_circuit::bytecode_unroller::{ @@ -57,7 +56,8 @@ use crate::bytecode_circuit::bytecode_unroller::{ use crate::evm_circuit::{table::FixedTableTag, witness::Block, EvmCircuit}; use crate::table::{ - load_block, load_keccaks, load_rws, BlockTable, BytecodeTable, KeccakTable, RwTable, TxTable, + load_block, load_copy, load_keccaks, load_rws, BlockTable, BytecodeTable, CopyTable, + KeccakTable, RwTable, TxTable, }; use crate::util::power_of_randomness_from_instance; use eth_types::Field; @@ -74,6 +74,7 @@ pub struct SuperCircuitConfig, tx_circuit: TxCircuitConfig, bytecode_circuit: BytecodeConfig, @@ -119,8 +120,8 @@ impl Circuit let bytecode_table = BytecodeTable::construct(meta); let block_table = BlockTable::construct(meta); let keccak_table = KeccakTable::construct(meta); - // TODO: Split CopyCircuit into a Table and the configuration. - let copy_table = CopyCircuit::configure(meta, &tx_table, &rw_table, &bytecode_table); + let q_copy_table = meta.fixed_column(); + let copy_table = CopyTable::construct(meta, q_copy_table); let power_of_randomness = power_of_randomness_from_instance(meta); let evm_circuit = EvmCircuit::configure( @@ -139,6 +140,7 @@ impl Circuit bytecode_table: bytecode_table.clone(), block_table, keccak_table: keccak_table.clone(), + copy_table, evm_circuit, tx_circuit: TxCircuitConfig::new( meta, @@ -189,9 +191,15 @@ impl Circuit &self.block.context, self.block.randomness, )?; + load_copy( + &config.copy_table, + &mut layouter, + &self.block, + self.block.randomness, + )?; config .evm_circuit - .assign_block_exact(&mut layouter, &self.block)?; + .assign_block(&mut layouter, &self.block)?; // --- Tx Circuit --- self.tx_circuit.assign(&config.tx_circuit, &mut layouter)?; // --- Bytecode Circuit --- diff --git a/zkevm-circuits/src/table.rs b/zkevm-circuits/src/table.rs index 8363e7093e..69f99ac0b0 100644 --- a/zkevm-circuits/src/table.rs +++ b/zkevm-circuits/src/table.rs @@ -3,13 +3,16 @@ // CHANGELOG: Move table definitions from evm_circuit/table.rs and rw_table.rs // to here +use crate::copy_circuit::number_or_hash_to_field; use crate::evm_circuit::witness::RwRow; use crate::evm_circuit::{ util::{rlc, RandomLinearCombination}, - witness::{BlockContext, Bytecode, RwMap, Transaction}, + witness::{Block, BlockContext, Bytecode, RwMap, Transaction}, }; use crate::impl_expr; -use eth_types::{Field, ToLittleEndian, Word}; +use bus_mapping::circuit_input_builder::{CopyDataType, CopyEvent}; +use eth_types::{Field, ToAddress, ToLittleEndian, ToScalar, Word, U256}; +use gadgets::binary_number::{BinaryNumberChip, BinaryNumberConfig}; use halo2_proofs::{ arithmetic::FieldExt, circuit::Region, @@ -20,22 +23,22 @@ use itertools::Itertools; use keccak256::plain::Keccak; use strum_macros::{EnumCount, EnumIter}; -// /// Trait used for dynamic tables. -// pub trait TableColumns { -// /// Returns the list of columns following the table order. This trait -// /// requires all the columns to be of the same type. -// fn columns(&self) -> Vec>; -// } - -/// Trait used to define lookup tables -pub trait LookupTable { +/// Trait used for dynamic tables. Used to get an automatic implementation of +/// the LookupTable trait where each `table_expr` is a query to each column at +/// `Rotation::cur`. +pub trait TableColumns { /// Returns the list of advice columns following the table order. - fn columns(&self) -> Vec> { - Vec::new() - } + fn columns(&self) -> Vec>; +} +/// Trait used to define lookup tables +pub trait LookupTable { /// Return the list of expressions used to define the lookup table. - fn table_exprs(&self, meta: &mut VirtualCells) -> Vec> { + fn table_exprs(&self, meta: &mut VirtualCells) -> Vec>; +} + +impl LookupTable for T { + fn table_exprs(&self, meta: &mut VirtualCells) -> Vec> { self.columns() .iter() .map(|column| meta.query_advice(*column, Rotation::cur())) @@ -43,15 +46,6 @@ pub trait LookupTable { } } -// impl> LookupTable for T { -// fn table_exprs(&self, meta: &mut VirtualCells) -> Vec> { -// self.columns() -// .iter() -// .map(|column| meta.query_advice(*column, Rotation::cur())) -// .collect() -// } -// } - impl> + Clone, const W: usize> LookupTable for [C; W] { fn table_exprs(&self, meta: &mut VirtualCells) -> Vec> { self.iter() @@ -120,7 +114,7 @@ impl TxTable { } } -impl LookupTable for TxTable { +impl TableColumns for TxTable { fn columns(&self) -> Vec> { vec![self.tx_id, self.tag, self.index, self.value] } @@ -344,7 +338,7 @@ pub struct RwTable { pub aux2: Column, } -impl LookupTable for RwTable { +impl TableColumns for RwTable { fn columns(&self) -> Vec> { vec![ self.rw_counter, @@ -481,7 +475,7 @@ impl BytecodeTable { } } -impl LookupTable for BytecodeTable { +impl TableColumns for BytecodeTable { fn columns(&self) -> Vec> { vec![ self.code_hash, @@ -589,7 +583,7 @@ impl BlockTable { } } -impl LookupTable for BlockTable { +impl TableColumns for BlockTable { fn columns(&self) -> Vec> { vec![self.tag, self.index, self.value] } @@ -659,7 +653,7 @@ impl KeccakTable { } } -impl LookupTable for KeccakTable { +impl TableColumns for KeccakTable { fn columns(&self) -> Vec> { vec![ self.is_enabled, @@ -741,37 +735,41 @@ pub fn load_keccaks<'a, F: Field>( /// Copy Table, used to verify copies of byte chunks between Memory, Bytecode, /// TxLogs and TxCallData. -#[derive(Clone, Debug)] +#[derive(Clone, Copy, Debug)] pub struct CopyTable { - /// Boolean value to indicate the first row in a copy event. + /// Whether the row is the first read-write pair for a copy event. pub is_first: Column, - /// Can be $txID, $callID, $codeHash (RLC encoded). + /// The relevant ID for the read-write row, represented as a random linear + /// combination. The ID may be one of the below: + /// 1. Call ID/Caller ID for CopyDataType::Memory + /// 2. RLC encoding of bytecode hash for CopyDataType::Bytecode + /// 3. Transaction ID for CopyDataType::TxCalldata, CopyDataType::TxLog pub id: Column, - /// Type of data source/destination, including Memory, Bytecode, TxCalldata, - /// TxLog. - pub tag: Column, - /// Address in the source data. Can be memory address, byte index in the - /// bytecode, tx call data, and tx log data. + /// The source/destination address for this copy step. Can be memory + /// address, byte index in the bytecode, tx call data, and tx log data. pub addr: Column, - /// Address boundary of the source data. Any data read from address greater - /// than or equal to this value will be 0. + /// The end of the source buffer for the copy event. Any data read from an + /// address greater than or equal to this value will be 0. pub src_addr_end: Column, - /// Number of bytes to be copied. + /// The number of bytes left to be copied. pub bytes_left: Column, - /// Current RW counter at the beginning of the copy + /// The associated read-write counter for this row. pub rw_counter: Column, - /// How much the RW counter will increase in a copy event. + /// Decrementing counter denoting reverse read-write counter. pub rwc_inc_left: Column, + /// Binary chip to constrain the copy table conditionally depending on the + /// current row's tag, whether it is Bytecode, Memory, TxCalldata or + /// TxLog. + pub tag: BinaryNumberConfig, } -/* impl CopyTable { /// Construct a new KeccakTable - pub fn construct(meta: &mut ConstraintSystem) -> Self { + pub fn construct(meta: &mut ConstraintSystem, q_enable: Column) -> Self { Self { is_first: meta.advice_column(), id: meta.advice_column(), - tag: meta.advice_column(), + tag: BinaryNumberChip::configure(meta, q_enable), addr: meta.advice_column(), src_addr_end: meta.advice_column(), bytes_left: meta.advice_column(), @@ -781,12 +779,11 @@ impl CopyTable { } } -impl TableColumns for CopyTable { +impl CopyTable { fn columns(&self) -> Vec> { vec![ self.is_first, self.id, - self.tag, self.addr, self.src_addr_end, self.bytes_left, @@ -813,4 +810,91 @@ impl LookupTable for CopyTable { ] } } -*/ + +/// Generate the keccak table assignments from a byte array input. +pub fn copy_table_assignments( + copy_event: &CopyEvent, + randomness: F, +) -> Vec<(CopyDataType, [F; 7])> { + let mut assignments = Vec::new(); + for (step_idx, copy_step) in copy_event.steps.iter().enumerate() { + // is_first + let is_first = if step_idx == 0 { F::one() } else { F::zero() }; + // id + let id = { + let id = if copy_step.rw.is_read() { + ©_event.src_id + } else { + ©_event.dst_id + }; + number_or_hash_to_field(id, randomness) + }; + // addr + let addr = match copy_step.tag { + CopyDataType::TxLog => { + let addr = (U256::from(copy_step.addr) + + (U256::from(TxLogFieldTag::Data as u64) << 32) + + (U256::from(copy_event.log_id.unwrap()) << 48)) + .to_address(); + addr.to_scalar().unwrap() + } + _ => F::from(copy_step.addr), + }; + assignments.push(( + copy_step.tag, + [ + is_first, + id, + addr, + F::from(copy_event.src_addr_end), // src_addr_end + F::from(copy_event.length - step_idx as u64 / 2), // bytes_left + F::from(copy_step.rwc.0 as u64), // rw_counter + F::from(copy_step.rwc_inc_left), // rw_inc_left + ], + )); + } + assignments +} + +/// Assign the `CopyTable` from a `Block`. +pub fn load_copy( + copy_table: &CopyTable, + layouter: &mut impl Layouter, + block: &Block, + randomness: F, +) -> Result<(), Error> { + layouter.assign_region( + || "copy table", + |mut region| { + let mut offset = 0; + for column in copy_table.columns() { + region.assign_advice( + || "copy table all-zero row", + column, + offset, + || Ok(F::zero()), + )?; + } + offset += 1; + + let tag_chip = BinaryNumberChip::construct(copy_table.tag); + let copy_table_columns = copy_table.columns(); + for copy_event in block.copy_events.values() { + for (tag, row) in copy_table_assignments(copy_event, randomness) { + for (column, value) in copy_table_columns.iter().zip_eq(row) { + region.assign_advice( + || format!("copy table row {}", offset), + *column, + offset, + || Ok(value), + )?; + } + tag_chip.assign(&mut region, offset, &tag)?; + offset += 1; + } + } + + Ok(()) + }, + ) +} From a04464fac7bb00075abb69bf803e72154a4122ae Mon Sep 17 00:00:00 2001 From: Eduard S Date: Wed, 20 Jul 2022 11:32:05 +0200 Subject: [PATCH 23/26] Mark super circuit test as serial --- zkevm-circuits/src/super_circuit.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/zkevm-circuits/src/super_circuit.rs b/zkevm-circuits/src/super_circuit.rs index d41d45ee54..cd1d29afb0 100644 --- a/zkevm-circuits/src/super_circuit.rs +++ b/zkevm-circuits/src/super_circuit.rs @@ -363,8 +363,11 @@ mod super_circuit_tests { run_test_circuit::(inputs, FixedTableTag::iter().collect()) } + // High memory usage test. Run in serial with: + // `cargo test [...] serial_ -- --ignored --test-threads 1` + #[ignore] #[test] - fn test_super_circuit() { + fn serial_test_super_circuit() { let mut rng = ChaCha20Rng::seed_from_u64(2); let chain_id = (*MOCK_CHAIN_ID).as_u64(); From a23dfa1c63cfa73e994938a00b999f14c2498f93 Mon Sep 17 00:00:00 2001 From: Eduard S Date: Wed, 20 Jul 2022 15:32:36 +0200 Subject: [PATCH 24/26] Introduce Super Circuit and adapt existing circuits for it The SuperCircuit is a new circuit that will contain all the circuits of the zkEVM in order to achieve two things: - Check the correct integration between circuits via the shared lookup tables - Allow having a single circuit setup for which a proof can be generated that would be verified under a single aggregation circuit for the first milestone Summary of changes: - general: - Addapt the circuits so that the shared tables can be assigned outside of the circuit's assign functions. - evm_circuit.rs - load table functions moved to `table.rs` - bytecode_circuit/bytecode_unroller.rs - Rename `hash_length` to `code_length` in `Config` - Rename `r` to `randomness` - Add `is_enabled` expression to the keccak lookup - Move `load_keccaks` to `table.rs` - Fix endianness in keccak hash output - Add function to obtain all the keccak inputs required by the `SignVerifyChip` - table.rs - Move table definitions from `evm_circuit/table.rs` and `rw_table.rs` to here - Move all shared table load functions to here - Add BytecodeTable to help reusing the table config with other - Rename `hash` to `code_hash` in `BytecodeTable` - Use `RLC(reversed(input))` in keccak table assignment for `input_rlc`. - tx_circuit.rs - Add function to obtain all the keccak inputs required by the `TxCircuit` - Fix `Gas` encoding: remove RLC - Add missing field `TxFieldTag::CallDataGasCost` - tx_circuit/sign_verify.rs - Move `load_keccak` to `table.rs` - Add function to obtain all the keccak inputs required by the `SignVerifyChip` - Reverse the `pk_hash` used in the lookup so that the RLC is calculated as if it was a hash in an Ethereum Word. --- .../src/circuit_input_builder/execution.rs | 2 +- rustfmt.toml | 1 - .../src/bytecode_circuit/bytecode_unroller.rs | 75 +-- zkevm-circuits/src/copy_circuit.rs | 26 +- zkevm-circuits/src/evm_circuit.rs | 44 +- .../execution/copy_code_to_memory.rs | 474 ------------- .../src/evm_circuit/execution/copy_to_log.rs | 465 ------------- .../src/evm_circuit/execution/memory_copy.rs | 498 -------------- zkevm-circuits/src/evm_circuit/util.rs | 5 - zkevm-circuits/src/evm_circuit/witness.rs | 5 +- zkevm-circuits/src/super_circuit.rs | 59 +- zkevm-circuits/src/table.rs | 632 +++++++++--------- zkevm-circuits/src/tx_circuit.rs | 20 +- zkevm-circuits/src/tx_circuit/sign_verify.rs | 91 +-- zkevm-circuits/src/util.rs | 69 +- 15 files changed, 362 insertions(+), 2104 deletions(-) delete mode 100644 zkevm-circuits/src/evm_circuit/execution/copy_code_to_memory.rs delete mode 100644 zkevm-circuits/src/evm_circuit/execution/copy_to_log.rs delete mode 100644 zkevm-circuits/src/evm_circuit/execution/memory_copy.rs diff --git a/bus-mapping/src/circuit_input_builder/execution.rs b/bus-mapping/src/circuit_input_builder/execution.rs index 1b34004d1c..9f21a3f42b 100644 --- a/bus-mapping/src/circuit_input_builder/execution.rs +++ b/bus-mapping/src/circuit_input_builder/execution.rs @@ -201,7 +201,7 @@ pub enum NumberOrHash { /// Defines a copy event associated with EVM opcodes such as CALLDATACOPY, /// CODECOPY, CREATE, etc. More information: -/// https://github.com/privacy-scaling-explorations/zkevm-specs/blob/master/specs/copy-proof.md. +/// . #[derive(Clone, Debug)] pub struct CopyEvent { /// Represents the start address at the source of the copy event. diff --git a/rustfmt.toml b/rustfmt.toml index 6171f88c92..22f8bbbcbe 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,4 +1,3 @@ max_width = 100 wrap_comments = true -normalize_comments = false edition = "2021" diff --git a/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs b/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs index 5f88224d56..cce4384b33 100644 --- a/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs +++ b/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs @@ -16,8 +16,6 @@ use halo2_proofs::{ use keccak256::plain::Keccak; use std::vec; -// use crate::util::TableShow; - use super::param::PUSH_TABLE_WIDTH; /// Public data for the bytecode @@ -47,7 +45,7 @@ pub struct Config { bytecode_table: BytecodeTable, push_rindex: Column, hash_input_rlc: Column, - code_length: Column, // CHANGELOG: Renamed from hash_length + code_length: Column, byte_push_size: Column, is_final: Column, padding: Column, @@ -59,8 +57,6 @@ pub struct Config { keccak_table: KeccakTable, } -// use crate::util::TableShow; - impl Config { pub(crate) fn configure( meta: &mut ConstraintSystem, @@ -352,7 +348,6 @@ impl Config { not::expr(meta.query_advice(padding, Rotation::cur())), ]); let lookup_columns = vec![hash_input_rlc, code_length, bytecode_table.code_hash]; - // CHANGELOG: Add is_enabled expression to the keccak lookup let mut constraints = vec![( enable.clone(), meta.query_advice(keccak_table.is_enabled, Rotation::cur()), @@ -406,10 +401,6 @@ impl Config { |mut region| { let mut offset = 0; let mut push_rindex_prev = 0; - // println!("> BytecodeConfig::assign"); - // let mut table = - // TableShow::::new(vec!["codeHash", "tag", "index", "isCode", "value"]); - for bytecode in witness.iter() { // Run over all the bytes let mut push_rindex = 0; @@ -454,11 +445,6 @@ impl Config { )?; push_rindex_prev = push_rindex; offset += 1; - // table.push(0, row.code_hash); - // table.push(1, row.tag); - // table.push(2, row.index); - // table.push(3, row.is_code); - // table.push(4, row.value); } } } @@ -486,13 +472,7 @@ impl Config { F::from(push_rindex_prev), )?; push_rindex_prev = 0; - // table.push(0, F::zero()); - // table.push(1, F::from(BytecodeFieldTag::Padding as u64)); - // table.push(2, F::zero()); - // table.push(3, F::one()); - // table.push(4, F::zero()); } - // table.print(); Ok(()) }, ) @@ -572,55 +552,12 @@ impl Config { Ok(()) } - // CHANGELOG: Moved to a new function to allow not calling it when integrating - // circuits together. - // pub(crate) fn load_keccaks( - // &self, - // layouter: &mut impl Layouter, - // bytecodes: &[UnrolledBytecode], - // randomness: F, - // ) -> Result<(), Error> { - // println!("> bytecode_circuit.load_keccaks"); - // let mut table = - // TableShow::::new(vec!["is_enabled", "input_rlc", "input_len", - // "output_rlc"]); layouter.assign_region( - // || "keccak table", - // |mut region| { - // for (offset, bytecode) in bytecodes.iter().map(|v| - // v.bytes.clone()).enumerate() { let code_hash: F = - // keccak(&bytecode[..], randomness); // println!("+ {:?}", - // bytecode); let input_rlc: F = - // rlc::value(bytecode.iter().rev(), randomness); let size = - // F::from(bytecode.len() as u64); for (name, column, value) - // in &[ ("is_enable", self.keccak_table.is_enabled, - // F::one()), ("input_rlc", self.keccak_table.input_rlc, - // input_rlc), ("input_len", - // self.keccak_table.input_len, size), ("output_rlc", - // self.keccak_table.output_rlc, code_hash), ] { - // region.assign_advice( - // || format!("Keccak table assign {} {}", name, - // offset), *column, - // offset, - // || Ok(*value), - // )?; - // } - // table.push(0, F::one()); - // table.push(1, input_rlc); - // table.push(2, size); - // table.push(3, code_hash); - // } - // table.print(); - // Ok(()) - // }, - // ) - // } - /// load fixed tables pub(crate) fn load(&self, layouter: &mut impl Layouter) -> Result<(), Error> { // push table: BYTE -> NUM_PUSHED: - // [0, OpcodeId::PUSH1[ -> 0 + // [0, OpcodeId::PUSH1] -> 0 // [OpcodeId::PUSH1, OpcodeId::PUSH32] -> [1..32] - // ]OpcodeId::PUSH32, 256[ -> 0 + // [OpcodeId::PUSH32, 256] -> 0 layouter.assign_region( || "push table", |mut region| { @@ -692,7 +629,6 @@ fn get_push_size(byte: u8) -> u64 { fn keccak(msg: &[u8], randomness: F) -> F { let mut keccak = Keccak::default(); keccak.update(msg); - // CHANGELOG: Fixed endianness RandomLinearCombination::::random_linear_combine( Word::from_big_endian(keccak.digest().as_slice()).to_le_bytes(), randomness, @@ -715,7 +651,7 @@ fn into_words(message: &[u8]) -> Vec { #[cfg(test)] mod tests { use super::*; - use crate::{table::load_keccaks, util::power_of_randomness_from_instance}; + use crate::util::power_of_randomness_from_instance; use eth_types::{Bytecode, Word}; use halo2_proofs::{ circuit::{Layouter, SimpleFloorPlanner}, @@ -764,8 +700,7 @@ mod tests { mut layouter: impl Layouter, ) -> Result<(), Error> { config.load(&mut layouter)?; - load_keccaks( - &config.keccak_table, + config.keccak_table.load( &mut layouter, self.bytecodes.iter().map(|b| b.bytes.as_slice()), self.randomness, diff --git a/zkevm-circuits/src/copy_circuit.rs b/zkevm-circuits/src/copy_circuit.rs index 83befc72dd..97c57cb93b 100644 --- a/zkevm-circuits/src/copy_circuit.rs +++ b/zkevm-circuits/src/copy_circuit.rs @@ -262,8 +262,7 @@ impl CopyCircuit { 1.expr(), RwTableTag::TxLog.expr(), meta.query_advice(id, Rotation::cur()), // tx_id - meta.query_advice(addr, Rotation::cur()), /* byte_index || field_tag || - * log_id */ + meta.query_advice(addr, Rotation::cur()), // byte_index || field_tag || log_id 0.expr(), 0.expr(), meta.query_advice(value, Rotation::cur()), @@ -605,7 +604,7 @@ mod tests { use crate::{ evm_circuit::witness::{block_convert, Block}, - table::{load_bytecodes, load_rws, load_txs, BytecodeTable, RwTable, TxTable}, + table::{BytecodeTable, RwTable, TxTable}, }; #[derive(Clone)] @@ -663,20 +662,13 @@ mod tests { config: Self::Config, mut layouter: impl Layouter, ) -> Result<(), halo2_proofs::plonk::Error> { - load_txs( - &config.tx_table, - &mut layouter, - &self.block.txs, - self.block.randomness, - )?; - load_rws( - &config.rw_table, - &mut layouter, - &self.block.rws, - self.block.randomness, - )?; - load_bytecodes( - &config.bytecode_table, + config + .tx_table + .load(&mut layouter, &self.block.txs, self.block.randomness)?; + config + .rw_table + .load(&mut layouter, &self.block.rws, self.block.randomness)?; + config.bytecode_table.load( &mut layouter, self.block.bytecodes.values(), self.block.randomness, diff --git a/zkevm-circuits/src/evm_circuit.rs b/zkevm-circuits/src/evm_circuit.rs index 106b659768..698fc82018 100644 --- a/zkevm-circuits/src/evm_circuit.rs +++ b/zkevm-circuits/src/evm_circuit.rs @@ -147,10 +147,7 @@ impl EvmCircuit { pub mod test { use crate::{ evm_circuit::{table::FixedTableTag, witness::Block, EvmCircuit}, - table::{ - load_block, load_bytecodes, load_copy, load_rws, load_txs, BlockTable, BytecodeTable, - CopyTable, RwTable, TxTable, - }, + table::{BlockTable, BytecodeTable, CopyTable, RwTable, TxTable}, util::power_of_randomness_from_instance, }; use eth_types::{Field, Word}; @@ -256,36 +253,23 @@ pub mod test { .evm_circuit .load_fixed_table(&mut layouter, self.fixed_table_tags.clone())?; config.evm_circuit.load_byte_table(&mut layouter)?; - load_txs( - &config.tx_table, - &mut layouter, - &self.block.txs, - self.block.randomness, - )?; - load_rws( - &config.rw_table, - &mut layouter, - &self.block.rws, - self.block.randomness, - )?; - load_bytecodes( - &config.bytecode_table, + config + .tx_table + .load(&mut layouter, &self.block.txs, self.block.randomness)?; + config + .rw_table + .load(&mut layouter, &self.block.rws, self.block.randomness)?; + config.bytecode_table.load( &mut layouter, self.block.bytecodes.iter().map(|(_, b)| b), self.block.randomness, )?; - load_block( - &config.block_table, - &mut layouter, - &self.block.context, - self.block.randomness, - )?; - load_copy( - &config.copy_table, - &mut layouter, - &self.block, - self.block.randomness, - )?; + config + .block_table + .load(&mut layouter, &self.block.context, self.block.randomness)?; + config + .copy_table + .load(&mut layouter, &self.block, self.block.randomness)?; config .evm_circuit .assign_block_exact(&mut layouter, &self.block) diff --git a/zkevm-circuits/src/evm_circuit/execution/copy_code_to_memory.rs b/zkevm-circuits/src/evm_circuit/execution/copy_code_to_memory.rs deleted file mode 100644 index 72914aaf1e..0000000000 --- a/zkevm-circuits/src/evm_circuit/execution/copy_code_to_memory.rs +++ /dev/null @@ -1,474 +0,0 @@ -use array_init::array_init; -use bus_mapping::{circuit_input_builder::CopyDetails, constants::MAX_COPY_BYTES}; -use eth_types::{Field, ToLittleEndian}; -use halo2_proofs::plonk::Error; - -use crate::{ - evm_circuit::{ - param::{N_BYTES_MEMORY_ADDRESS, N_BYTES_MEMORY_WORD_SIZE}, - step::ExecutionState, - util::{ - constraint_builder::{ConstraintBuilder, StepStateTransition, Transition}, - math_gadget::ComparisonGadget, - memory_gadget::BufferReaderGadget, - CachedRegion, Cell, Word, - }, - witness::{Block, Call, ExecStep, Transaction}, - }, - util::Expr, -}; - -use super::ExecutionGadget; - -#[derive(Clone, Debug)] -/// This gadget is responsible for copying bytes from an account's code to -/// memory. This is an internal gadget used by the `CodeCopyGadget`. -pub(crate) struct CopyCodeToMemoryGadget { - /// Offset in the source (bytecode) to read from. - src_addr: Cell, - /// Offset in the destination (memory) to write to. - dst_addr: Cell, - /// Number of bytes left to be copied in this iteration. - bytes_left: Cell, - /// Source (bytecode) bytes end here. - src_addr_end: Cell, - /// Keccak-256 hash of the bytecode source. - code_hash: Word, - /// Array of booleans to mark whether or not the byte in question is an - /// opcode byte or an argument that follows the opcode. For example, - /// `is_code = true` for `POP`, `is_code = true` for `PUSH32`, but - /// `is_code = false` for the 32 bytes that follow the `PUSH32` opcode. - is_codes: [Cell; MAX_COPY_BYTES], - /// Gadget to assign bytecode to buffer and read byte-by-byte. - buffer_reader: BufferReaderGadget, - /// Comparison gadget to conditionally stop this iterative internal step - /// once all the bytes have been copied. - finish_gadget: ComparisonGadget, -} - -impl ExecutionGadget for CopyCodeToMemoryGadget { - const NAME: &'static str = "COPYCODETOMEMORY"; - - const EXECUTION_STATE: ExecutionState = ExecutionState::CopyCodeToMemory; - - fn configure(cb: &mut ConstraintBuilder) -> Self { - // Query cells for the internal step's auxiliary data and construct the buffer - // reader. - let src_addr = cb.query_cell(); - let dst_addr = cb.query_cell(); - let bytes_left = cb.query_cell(); - let src_addr_end = cb.query_cell(); - let code_hash = cb.query_word(); - let is_codes = array_init(|_| cb.query_bool()); - let buffer_reader = BufferReaderGadget::construct(cb, src_addr.expr(), src_addr_end.expr()); - - // For every byte in the bytecode's span covered in this iteration. - for (idx, is_code) in is_codes.iter().enumerate() { - // Lookup the bytecode table for the byte value read at the appropriate source - // memory address from the buffer. - cb.condition(buffer_reader.read_flag(idx), |cb| { - cb.bytecode_lookup( - code_hash.expr(), - src_addr.expr() + idx.expr(), - is_code.expr(), - buffer_reader.byte(idx), - ); - }); - // Lookup the RW table for a memory write operation at the appropriate - // destination memory address. - cb.condition(buffer_reader.has_data(idx), |cb| { - cb.memory_lookup( - 1.expr(), - dst_addr.expr() + idx.expr(), - buffer_reader.byte(idx), - None, - ); - }); - } - - // Construct the comparison gadget using the number of bytes copied in this - // iteration and the number bytes that were left to be copied before the - // start of this iteration. - let copied_size = buffer_reader.num_bytes(); - let finish_gadget = ComparisonGadget::construct(cb, copied_size.clone(), bytes_left.expr()); - let (lt, finished) = finish_gadget.expr(); - - // We should have continued only until there were no more bytes left to be - // copied. In case the copied size was less than the number of bytes - // left, the iterative process should not be finished. - cb.add_constraint( - "Constrain num_bytes <= bytes_left", - (1.expr() - lt) * (1.expr() - finished.clone()), - ); - - // If the iterative process has not yet finished, we constrain the next step to - // be another `CopyCodeToMemory` while adding some additional - // constraints to the auxiliary data. - cb.constrain_next_step( - ExecutionState::CopyCodeToMemory, - Some(1.expr() - finished), - |cb| { - let next_src_addr = cb.query_cell(); - let next_dst_addr = cb.query_cell(); - let next_bytes_left = cb.query_cell(); - let next_src_addr_end = cb.query_cell(); - let next_code_hash = cb.query_word(); - - cb.require_equal( - "next_src_addr == src_addr + copied_size", - next_src_addr.expr(), - src_addr.expr() + copied_size.clone(), - ); - cb.require_equal( - "dst_addr + copied_size == next_dst_addr", - next_dst_addr.expr(), - dst_addr.expr() + copied_size.clone(), - ); - cb.require_equal( - "next_bytes_left == bytes_left - copied_size", - next_bytes_left.expr(), - bytes_left.expr() - copied_size.clone(), - ); - cb.require_equal( - "next_src_addr_end == src_addr_end", - next_src_addr_end.expr(), - src_addr_end.expr(), - ); - cb.require_equal( - "next_code_hash == code_hash", - next_code_hash.expr(), - code_hash.expr(), - ); - }, - ); - - // Since this is an internal step for `CODECOPY` opcode, we only increment the - // RW counter. The program counter, stack pointer, and other fields do - // not change. - let step_state_transition = StepStateTransition { - rw_counter: Transition::Delta(cb.rw_counter_offset()), - ..Default::default() - }; - cb.require_step_state_transition(step_state_transition); - - Self { - src_addr, - dst_addr, - bytes_left, - src_addr_end, - code_hash, - is_codes, - buffer_reader, - finish_gadget, - } - } - - fn assign_exec_step( - &self, - region: &mut CachedRegion<'_, '_, F>, - offset: usize, - block: &Block, - _tx: &Transaction, - _call: &Call, - step: &ExecStep, - ) -> Result<(), Error> { - // Read the auxiliary data. - let aux = if step.aux_data.is_none() { - // TODO: Handle error correctly returning err - unreachable!("could not find aux_data for this step") - } else { - step.aux_data.unwrap() - }; - - let code_hash = match aux.copy_details() { - CopyDetails::Code(code) => code, - _ => unreachable!("the source has to come from code not calldata"), - }; - - let code = block - .bytecodes - .get(&code_hash) - .unwrap_or_else(|| panic!("could not find bytecode with hash={:?}", code_hash)); - // Assign to the appropriate cells. - self.src_addr - .assign(region, offset, Some(F::from(aux.src_addr())))?; - self.dst_addr - .assign(region, offset, Some(F::from(aux.dst_addr())))?; - self.bytes_left - .assign(region, offset, Some(F::from(aux.bytes_left())))?; - self.src_addr_end - .assign(region, offset, Some(F::from(aux.src_addr_end())))?; - self.code_hash - .assign(region, offset, Some(code.hash.to_le_bytes()))?; - - // Initialise selectors and bytes for the buffer reader. - let mut selectors = vec![false; MAX_COPY_BYTES]; - let mut bytes = vec![0u8; MAX_COPY_BYTES]; - let is_codes = code - .table_assignments(block.randomness) - .iter() - .skip(1) - .map(|c| c[3]) - .collect::>(); - for idx in 0..std::cmp::min(aux.bytes_left() as usize, MAX_COPY_BYTES) { - selectors[idx] = true; - let addr = aux.src_addr() as usize + idx; - bytes[idx] = if addr < aux.src_addr_end() as usize { - assert!(addr < code.bytes.len()); - self.is_codes[idx].assign(region, offset, Some(is_codes[addr]))?; - code.bytes[addr] - } else { - 0 - }; - } - - self.buffer_reader.assign( - region, - offset, - aux.src_addr(), - aux.src_addr_end(), - &bytes, - &selectors, - )?; - - // The number of bytes copied here will be the sum of 1s over the selector - // vector. - let num_bytes_copied = std::cmp::min(aux.bytes_left(), MAX_COPY_BYTES as u64); - - // Assign the comparison gadget. - self.finish_gadget.assign( - region, - offset, - F::from(num_bytes_copied), - F::from(aux.bytes_left()), - )?; - - Ok(()) - } -} - -#[cfg(test)] -pub(crate) mod test { - use super::MAX_COPY_BYTES; - use std::collections::HashMap; - - use bus_mapping::{ - circuit_input_builder::{CopyDetails, StepAuxiliaryData}, - evm::OpcodeId, - }; - use eth_types::{bytecode, Word}; - use halo2_proofs::arithmetic::BaseExt; - use halo2_proofs::pairing::bn256::Fr; - - use crate::{ - evm_circuit::{ - step::ExecutionState, - test::run_test_circuit_incomplete_fixed_table, - witness::{Block, Bytecode, Call, ExecStep, Rw, RwMap, Transaction}, - }, - table::RwTableTag, - }; - - #[allow(clippy::too_many_arguments)] - pub(crate) fn make_copy_code_step( - call_id: usize, - src_addr: u64, - dst_addr: u64, - src_addr_end: u64, - bytes_left: usize, - program_counter: u64, - stack_pointer: usize, - memory_size: u64, - rw_counter: usize, - rws: &mut RwMap, - bytes_map: &HashMap, - code: &Bytecode, - ) -> (ExecStep, usize) { - let mut rw_offset = 0usize; - let memory_rws: &mut Vec<_> = rws.0.entry(RwTableTag::Memory).or_insert_with(Vec::new); - let rw_idx_start = memory_rws.len(); - - for idx in 0..std::cmp::min(bytes_left, MAX_COPY_BYTES) { - let addr = src_addr + idx as u64; - let byte = if addr < src_addr_end { - assert!(bytes_map.contains_key(&addr)); - bytes_map[&addr] - } else { - 0 - }; - memory_rws.push(Rw::Memory { - rw_counter: rw_counter + rw_offset, - is_write: true, - call_id, - memory_address: dst_addr + idx as u64, - byte, - }); - rw_offset += 1; - } - - let rw_idx_end = rws.0[&RwTableTag::Memory].len(); - let aux_data = StepAuxiliaryData::new( - src_addr, - dst_addr, - bytes_left as u64, - src_addr_end, - CopyDetails::Code(code.hash), - ); - let step = ExecStep { - execution_state: ExecutionState::CopyCodeToMemory, - rw_indices: (rw_idx_start..rw_idx_end) - .map(|idx| (RwTableTag::Memory, idx)) - .collect(), - rw_counter, - program_counter, - stack_pointer, - memory_size, - gas_cost: 0, - aux_data: Some(aux_data), - ..Default::default() - }; - - (step, rw_offset) - } - - #[allow(clippy::too_many_arguments)] - pub(crate) fn make_copy_code_steps( - call_id: usize, - code: &Bytecode, - src_addr: u64, - dst_addr: u64, - length: usize, - program_counter: u64, - stack_pointer: usize, - memory_size: u64, - rw_counter: &mut usize, - rws: &mut RwMap, - steps: &mut Vec, - ) { - let bytes_map = (0..(code.bytes.len() as u64)) - .zip(code.bytes.iter().copied()) - .collect(); - - let mut copied = 0; - while copied < length { - let (step, rw_offset) = make_copy_code_step( - call_id, - src_addr + copied as u64, - dst_addr + copied as u64, - code.bytes.len() as u64, - length - copied, - program_counter, - stack_pointer, - memory_size, - *rw_counter, - rws, - &bytes_map, - code, - ); - steps.push(step); - *rw_counter += rw_offset; - copied += MAX_COPY_BYTES; - } - } - - fn test_ok(src_addr: u64, dst_addr: u64, length: usize) { - let randomness = Fr::rand(); - let call_id = 1; - let mut rws = RwMap::default(); - let mut rw_counter = 1; - let mut steps = Vec::new(); - let memory_size = (dst_addr + length as u64 + 31) / 32 * 32; - - // generate random bytecode longer than `src_addr_end` - let code = bytecode! { - PUSH32(Word::from(0x123)) - POP - PUSH32(Word::from(0x213)) - POP - PUSH32(Word::from(0x321)) - POP - PUSH32(Word::from(0x12349AB)) - POP - PUSH32(Word::from(0x1928835)) - POP - }; - - let code = Bytecode::new(code.to_vec()); - let dummy_code = Bytecode::new(vec![OpcodeId::RETURN.as_u8()]); - - let program_counter = 0; - let stack_pointer = 1024; - make_copy_code_steps( - call_id, - &code, - src_addr, - dst_addr, - length, - program_counter, - stack_pointer, - memory_size, - &mut rw_counter, - &mut rws, - &mut steps, - ); - - steps.push(ExecStep { - execution_state: ExecutionState::RETURN, - rw_counter, - program_counter, - stack_pointer, - memory_size, - opcode: Some(OpcodeId::RETURN), - ..Default::default() - }); - - let block = Block { - randomness, - txs: vec![Transaction { - id: 1, - calls: vec![Call { - id: call_id, - is_root: true, - is_create: false, - code_hash: dummy_code.hash, - ..Default::default() - }], - steps, - ..Default::default() - }], - rws, - bytecodes: HashMap::from_iter([(dummy_code.hash, dummy_code), (code.hash, code)]), - ..Default::default() - }; - assert_eq!(run_test_circuit_incomplete_fixed_table(block), Ok(())); - } - - #[test] - fn copy_code_to_memory_single_step() { - test_ok( - 0x00, // src_addr - 0x00, // dst_addr - 54, // length - ); - } - - #[test] - fn copy_code_to_memory_multi_step() { - test_ok( - 0x00, // src_addr - 0x40, // dst_addr - 123, // length - ); - } - - #[test] - fn copy_code_to_memory_oob() { - // since the bytecode we construct above is (34 * 5) = 170 bytes long, copying - // 200 bytes means we go out-of-bounds. - test_ok( - 0x10, // src_addr - 0x20, // dst_addr - 200, // length - ); - } -} diff --git a/zkevm-circuits/src/evm_circuit/execution/copy_to_log.rs b/zkevm-circuits/src/evm_circuit/execution/copy_to_log.rs deleted file mode 100644 index e89fdaac3c..0000000000 --- a/zkevm-circuits/src/evm_circuit/execution/copy_to_log.rs +++ /dev/null @@ -1,465 +0,0 @@ -use crate::{ - evm_circuit::{ - execution::ExecutionGadget, - param::{N_BYTES_MEMORY_ADDRESS, N_BYTES_MEMORY_WORD_SIZE}, - step::ExecutionState, - util::{ - constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, - math_gadget::ComparisonGadget, - memory_gadget::BufferReaderGadget, - CachedRegion, Cell, - }, - witness::{Block, Call, ExecStep, Transaction}, - }, - table::TxLogFieldTag, - util::Expr, -}; -use bus_mapping::{circuit_input_builder::CopyDetails, constants::MAX_COPY_BYTES}; -use eth_types::Field; -use halo2_proofs::plonk::Error; - -/// Multi-step gadget for copying data from memory to RW log -#[derive(Clone, Debug)] -pub(crate) struct CopyToLogGadget { - // The src memory address to copy from - src_addr: Cell, - // The number of bytes left to copy - bytes_left: Cell, - // The src address bound of the buffer - src_addr_end: Cell, - // the call is persistent or not - is_persistent: Cell, - // The tx id - tx_id: Cell, - // the log data start index fetched from last step - data_start_index: Cell, - // Buffer reader gadget - buffer_reader: BufferReaderGadget, - // The comparison gadget between num bytes copied and bytes_left - finish_gadget: ComparisonGadget, -} - -impl ExecutionGadget for CopyToLogGadget { - const NAME: &'static str = "CopyToLogGadget"; - - const EXECUTION_STATE: ExecutionState = ExecutionState::CopyToLog; - - fn configure(cb: &mut ConstraintBuilder) -> Self { - let src_addr = cb.query_cell(); - let bytes_left = cb.query_cell(); - let src_addr_end = cb.query_cell(); - let is_persistent = cb.query_bool(); - let tx_id = cb.query_cell(); - let data_start_index = cb.query_cell(); - let buffer_reader = BufferReaderGadget::construct(cb, src_addr.expr(), src_addr_end.expr()); - - // Copy bytes from src and dst - for i in 0..MAX_COPY_BYTES { - let read_flag = buffer_reader.read_flag(i); - // Read bytes[i] from memory - cb.condition(read_flag.clone(), |cb| { - cb.memory_lookup( - 0.expr(), - src_addr.expr() + i.expr(), - buffer_reader.byte(i), - None, - ) - }); - - // Write bytes[i] to log when selectors[i] != 0 and is_persistent = true - cb.condition(buffer_reader.has_data(i) * is_persistent.expr(), |cb| { - cb.tx_log_lookup( - tx_id.expr(), - cb.curr.state.log_id.expr(), - TxLogFieldTag::Data, - data_start_index.expr() + i.expr(), - buffer_reader.byte(i), - ) - }); - } - - let copied_size = buffer_reader.num_bytes(); - let finish_gadget = ComparisonGadget::construct(cb, copied_size.clone(), bytes_left.expr()); - let (lt, finished) = finish_gadget.expr(); - // Constrain lt == 1 or finished == 1 - cb.add_constraint( - "Constrain num_bytes <= bytes_left", - (1.expr() - lt) * (1.expr() - finished.clone()), - ); - - // When finished == 0, constraint the CopyToLog state in next step - cb.constrain_next_step(ExecutionState::CopyToLog, Some(1.expr() - finished), |cb| { - let next_src_addr = cb.query_cell(); - let next_bytes_left = cb.query_cell(); - let next_src_addr_end = cb.query_cell(); - let next_is_persistent = cb.query_bool(); - let next_tx_id = cb.query_cell(); - let next_data_start_index = cb.query_cell(); - - cb.require_equal( - "next_src_addr == src_addr + copied_size", - next_src_addr.expr(), - src_addr.expr() + copied_size.clone(), - ); - - cb.require_equal( - "next_bytes_left == bytes_left - copied_size", - next_bytes_left.expr(), - bytes_left.expr() - copied_size.clone(), - ); - cb.require_equal( - "next_src_addr_end == src_addr_end", - next_src_addr_end.expr(), - src_addr_end.expr(), - ); - cb.require_equal( - "next_is_persistent == is_persistent", - next_is_persistent.expr(), - is_persistent.expr(), - ); - cb.require_equal("next_tx_id == tx_id", next_tx_id.expr(), tx_id.expr()); - cb.require_equal( - "next_data_start_index == data_start_index + MAX_COPY_BYTES - ", - next_data_start_index.expr(), - data_start_index.expr() + MAX_COPY_BYTES.expr(), - ); - }); - - // State transition - let step_state_transition = StepStateTransition { - rw_counter: Delta(cb.rw_counter_offset()), - ..Default::default() - }; - cb.require_step_state_transition(step_state_transition); - - Self { - src_addr, - bytes_left, - src_addr_end, - is_persistent, - tx_id, - data_start_index, - buffer_reader, - finish_gadget, - } - } - - fn assign_exec_step( - &self, - region: &mut CachedRegion<'_, '_, F>, - offset: usize, - block: &Block, - _: &Transaction, - _: &Call, - step: &ExecStep, - ) -> Result<(), Error> { - // Read the auxiliary data. - let aux = if step.aux_data.is_none() { - // TODO: Handle error correctly returning err - unreachable!("could not find aux_data for this step") - } else { - step.aux_data.unwrap() - }; - - // log won't use dst_addr - assert!(aux.dst_addr() == 0u64); - let (is_persistent, tx_id, data_start_index) = match aux.copy_details() { - CopyDetails::Log((is_persistent, tx_id, data_index)) => { - (is_persistent, tx_id, data_index) - } - _ => unreachable!("the data copy is not related to a LOG op"), - }; - - self.src_addr - .assign(region, offset, Some(F::from(aux.src_addr())))?; - self.bytes_left - .assign(region, offset, Some(F::from(aux.bytes_left())))?; - self.src_addr_end - .assign(region, offset, Some(F::from(aux.src_addr_end())))?; - self.is_persistent - .assign(region, offset, Some(F::from(is_persistent as u64)))?; - self.tx_id - .assign(region, offset, Some(F::from(tx_id as u64)))?; - self.data_start_index - .assign(region, offset, Some(F::from(data_start_index as u64)))?; - // Retrieve the bytes and selectors - - let mut rw_idx = 0; - let mut bytes = vec![0u8; MAX_COPY_BYTES]; - let mut selectors = vec![false; MAX_COPY_BYTES]; - - for idx in 0..std::cmp::min(aux.bytes_left() as usize, MAX_COPY_BYTES) { - let src_addr = aux.src_addr() as usize + idx; - selectors[idx] = true; - bytes[idx] = if selectors[idx] && src_addr < aux.src_addr_end() as usize { - let index = step.rw_indices[rw_idx]; - if is_persistent { - rw_idx += 2; - } else { - rw_idx += 1; - } - - block.rws[index].memory_value() - } else { - 0 - }; - } - - self.buffer_reader.assign( - region, - offset, - aux.src_addr(), - aux.src_addr_end(), - &bytes, - &selectors, - )?; - - let num_bytes_copied = std::cmp::min(aux.bytes_left(), MAX_COPY_BYTES as u64); - self.finish_gadget.assign( - region, - offset, - F::from(num_bytes_copied), - F::from(aux.bytes_left()), - )?; - - Ok(()) - } -} - -#[cfg(test)] -pub mod test { - use crate::{ - evm_circuit::{ - step::ExecutionState, - test::{rand_bytes, run_test_circuit_incomplete_fixed_table}, - witness::{Block, Bytecode, Call, ExecStep, Rw, RwMap, Transaction}, - }, - table::{RwTableTag, TxLogFieldTag}, - }; - use bus_mapping::{ - circuit_input_builder::{CopyDetails, StepAuxiliaryData}, - constants::MAX_COPY_BYTES, - }; - use eth_types::{evm_types::OpcodeId, Word}; - use halo2_proofs::arithmetic::BaseExt; - use halo2_proofs::pairing::bn256::Fr; - use std::collections::HashMap; - use std::convert::TryInto; - - #[allow(clippy::too_many_arguments)] - fn make_log_copy_step( - call_id: usize, - src_addr: u64, - src_addr_end: u64, - bytes_left: usize, - data_start_index: usize, - program_counter: u64, - stack_pointer: usize, - memory_size: u64, - rw_counter: usize, - rws: &mut RwMap, - bytes_map: &HashMap, - log_id: u64, - is_persistent: bool, - tx_id: usize, - ) -> (ExecStep, usize) { - let mut selectors = vec![0u8; MAX_COPY_BYTES]; - let mut rw_offset: usize = 0; - let memory_rws: &mut Vec<_> = rws.0.entry(RwTableTag::Memory).or_insert_with(Vec::new); - let mut txlog_rws: Vec = Vec::new(); - let mut rw_indices: Vec<(RwTableTag, usize)> = Vec::new(); - let mut memory_index = 0; - let mut log_data_index = 0; - - for (idx, selector) in selectors.iter_mut().enumerate() { - if idx < bytes_left { - *selector = 1; - let addr = src_addr + idx as u64; - let byte = if addr < src_addr_end { - assert!(bytes_map.contains_key(&addr)); - memory_rws.push(Rw::Memory { - rw_counter: rw_counter + rw_offset, - is_write: false, - call_id, - memory_address: src_addr + idx as u64, - byte: bytes_map[&addr], - }); - rw_indices.push((RwTableTag::Memory, memory_index + data_start_index)); - memory_index += 1; - rw_offset += 1; - bytes_map[&addr] - } else { - 0 - }; - if is_persistent { - txlog_rws.push(Rw::TxLog { - rw_counter: rw_counter + rw_offset, - is_write: true, - tx_id, - log_id, - field_tag: TxLogFieldTag::Data, - index: data_start_index + idx, - value: Word::from(byte), - }); - rw_indices.push((RwTableTag::TxLog, log_data_index + data_start_index)); - log_data_index += 1; - rw_offset += 1; - } - } - } - let log_rws: &mut Vec<_> = rws.0.entry(RwTableTag::TxLog).or_insert_with(Vec::new); - log_rws.extend(txlog_rws); - - let aux_data = StepAuxiliaryData::new( - src_addr, - Default::default(), - bytes_left as u64, - src_addr_end, - CopyDetails::Log((is_persistent, tx_id, data_start_index)), - ); - - let step = ExecStep { - execution_state: ExecutionState::CopyToLog, - rw_indices, - rw_counter, - program_counter, - stack_pointer, - memory_size, - gas_cost: 0, - log_id: if is_persistent { - log_id.try_into().unwrap() - } else { - 0 - }, - aux_data: Some(aux_data), - ..Default::default() - }; - (step, rw_offset) - } - - #[allow(clippy::too_many_arguments)] - pub(crate) fn make_log_copy_steps( - call_id: usize, - buffer: &[u8], - buffer_addr: u64, - src_addr: u64, - length: usize, - program_counter: u64, - stack_pointer: usize, - memory_size: u64, - rw_counter: &mut usize, - rws: &mut RwMap, - steps: &mut Vec, - log_id: u64, - is_persistent: bool, - tx_id: usize, - ) { - let buffer_addr_end = buffer_addr + buffer.len() as u64; - let bytes_map = (buffer_addr..buffer_addr_end) - .zip(buffer.iter().copied()) - .collect(); - - let mut copied = 0; - while copied < length { - let (step, rw_offset) = make_log_copy_step( - call_id, - src_addr + copied as u64, - buffer_addr_end, - length - copied, - copied, - program_counter, - stack_pointer, - memory_size, - *rw_counter, - rws, - &bytes_map, - log_id, - is_persistent, - tx_id, - ); - steps.push(step); - *rw_counter += rw_offset; - copied += MAX_COPY_BYTES; - } - } - - fn test_ok_copy_to_log(src_addr: u64, src_addr_end: u64, length: usize, is_persistent: bool) { - let randomness = Fr::rand(); - let bytecode = Bytecode::new(vec![OpcodeId::RETURN.as_u8()]); - let call_id = 1; - let mut rws = RwMap(Default::default()); - let mut rw_counter = 1; - let mut steps = Vec::new(); - let tx_id = 1; - let log_id = 0; - let buffer = rand_bytes((src_addr_end - src_addr) as usize); - let memory_size = (src_addr + length as u64 + 31) / 32 * 32; - - make_log_copy_steps( - call_id, - &buffer, - src_addr, - src_addr, - length, - 0, - 1023, - memory_size, - &mut rw_counter, - &mut rws, - &mut steps, - log_id, - is_persistent, - tx_id, - ); - - steps.push(ExecStep { - execution_state: ExecutionState::RETURN, - rw_counter, - program_counter: 0, - stack_pointer: 1023, - memory_size, - opcode: Some(OpcodeId::RETURN), - ..Default::default() - }); - - let block = Block { - randomness, - txs: vec![Transaction { - id: 1, - calls: vec![Call { - id: call_id, - is_root: false, - is_create: false, - code_hash: bytecode.hash, - ..Default::default() - }], - steps, - ..Default::default() - }], - rws, - bytecodes: HashMap::from_iter([(bytecode.hash, bytecode)]), - ..Default::default() - }; - assert_eq!(run_test_circuit_incomplete_fixed_table(block), Ok(())); - } - - #[test] - fn copy_to_log_simple() { - // is_persistent = true - test_ok_copy_to_log(0x10, 0x30, 0x2, true); - test_ok_copy_to_log(0x100, 0x180, 0x40, true); - // is_persistent = false - test_ok_copy_to_log(0x10, 0x30, 0x2, false); - test_ok_copy_to_log(0x100, 0x180, 0x40, false); - } - - #[test] - fn copy_to_log_multi_step() { - // is_persistent = true - test_ok_copy_to_log(0x20, 0xA0, 80, true); - test_ok_copy_to_log(0x10, 0xA0, 160, true); - // is_persistent = false - test_ok_copy_to_log(0x20, 0xA0, 80, false); - } -} diff --git a/zkevm-circuits/src/evm_circuit/execution/memory_copy.rs b/zkevm-circuits/src/evm_circuit/execution/memory_copy.rs deleted file mode 100644 index e0ed7bba91..0000000000 --- a/zkevm-circuits/src/evm_circuit/execution/memory_copy.rs +++ /dev/null @@ -1,498 +0,0 @@ -use crate::{ - evm_circuit::{ - execution::ExecutionGadget, - param::{N_BYTES_MEMORY_ADDRESS, N_BYTES_MEMORY_WORD_SIZE}, - step::ExecutionState, - util::{ - constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, - math_gadget::ComparisonGadget, - memory_gadget::BufferReaderGadget, - CachedRegion, Cell, - }, - witness::{Block, Call, ExecStep, Transaction}, - }, - table::TxContextFieldTag, - util::Expr, -}; -use bus_mapping::{circuit_input_builder::CopyDetails, constants::MAX_COPY_BYTES}; -use eth_types::Field; -use halo2_proofs::plonk::Error; - -/// Multi-step gadget for copying data from memory or Tx calldata to memory -#[derive(Clone, Debug)] -pub(crate) struct CopyToMemoryGadget { - // The src memory address to copy from - src_addr: Cell, - // The dst memory address to copy to - dst_addr: Cell, - // The number of bytes left to copy - bytes_left: Cell, - // The src address bound of the buffer - src_addr_end: Cell, - // Indicate whether src is from Tx Calldata - from_tx: Cell, - // Source from where we read the bytes. This equals the tx ID in case of a root call, or caller - // ID in case of an internal call - src_id: Cell, - // Buffer reader gadget - buffer_reader: BufferReaderGadget, - // The comparison gadget between num bytes copied and bytes_left - finish_gadget: ComparisonGadget, -} - -impl ExecutionGadget for CopyToMemoryGadget { - const NAME: &'static str = "COPYTOMEMORY"; - - const EXECUTION_STATE: ExecutionState = ExecutionState::CopyToMemory; - - fn configure(cb: &mut ConstraintBuilder) -> Self { - let src_addr = cb.query_cell(); - let dst_addr = cb.query_cell(); - let bytes_left = cb.query_cell(); - let src_addr_end = cb.query_cell(); - let from_tx = cb.query_bool(); - let src_id = cb.query_cell(); - let buffer_reader = BufferReaderGadget::construct(cb, src_addr.expr(), src_addr_end.expr()); - let from_memory = 1.expr() - from_tx.expr(); - - // Copy bytes from src and dst - for i in 0..MAX_COPY_BYTES { - let read_flag = buffer_reader.read_flag(i); - // Read bytes[i] from memory - cb.condition(from_memory.clone() * read_flag.clone(), |cb| { - cb.memory_lookup( - 0.expr(), - src_addr.expr() + i.expr(), - buffer_reader.byte(i), - Some(src_id.expr()), - ) - }); - // Read bytes[i] from Tx - cb.condition(from_tx.expr() * read_flag.clone(), |cb| { - cb.tx_context_lookup( - src_id.expr(), - TxContextFieldTag::CallData, - Some(src_addr.expr() + i.expr()), - buffer_reader.byte(i), - ) - }); - // Write bytes[i] to memory when selectors[i] != 0 - cb.condition(buffer_reader.has_data(i), |cb| { - cb.memory_lookup( - 1.expr(), - dst_addr.expr() + i.expr(), - buffer_reader.byte(i), - None, - ) - }); - } - - let copied_size = buffer_reader.num_bytes(); - let finish_gadget = ComparisonGadget::construct(cb, copied_size.clone(), bytes_left.expr()); - let (lt, finished) = finish_gadget.expr(); - // Constrain lt == 1 or finished == 1 - cb.add_constraint( - "Constrain num_bytes <= bytes_left", - (1.expr() - lt) * (1.expr() - finished.clone()), - ); - - // When finished == 0, constraint the CopyToMemory state in next step - cb.constrain_next_step( - ExecutionState::CopyToMemory, - Some(1.expr() - finished), - |cb| { - let next_src_addr = cb.query_cell(); - let next_dst_addr = cb.query_cell(); - let next_bytes_left = cb.query_cell(); - let next_src_addr_end = cb.query_cell(); - let next_from_tx = cb.query_cell(); - let next_src_id = cb.query_cell(); - cb.require_equal( - "next_src_addr == src_addr + copied_size", - next_src_addr.expr(), - src_addr.expr() + copied_size.clone(), - ); - cb.require_equal( - "dst_addr + copied_size == next_dst_addr", - next_dst_addr.expr(), - dst_addr.expr() + copied_size.clone(), - ); - cb.require_equal( - "next_bytes_left == bytes_left - copied_size", - next_bytes_left.expr(), - bytes_left.expr() - copied_size.clone(), - ); - cb.require_equal( - "next_src_addr_end == src_addr_end", - next_src_addr_end.expr(), - src_addr_end.expr(), - ); - cb.require_equal( - "next_from_tx == from_tx", - next_from_tx.expr(), - from_tx.expr(), - ); - cb.require_equal("next_src_id == src_id", next_src_id.expr(), src_id.expr()); - }, - ); - - // State transition - let step_state_transition = StepStateTransition { - rw_counter: Delta(cb.rw_counter_offset()), - ..Default::default() - }; - cb.require_step_state_transition(step_state_transition); - - Self { - src_addr, - dst_addr, - bytes_left, - src_addr_end, - from_tx, - src_id, - buffer_reader, - finish_gadget, - } - } - - fn assign_exec_step( - &self, - region: &mut CachedRegion<'_, '_, F>, - offset: usize, - block: &Block, - tx: &Transaction, - call: &Call, - step: &ExecStep, - ) -> Result<(), Error> { - // Read the auxiliary data. - let aux = if step.aux_data.is_none() { - // TODO: Handle error correctly returning err - unreachable!("could not find aux_data for this step") - } else { - step.aux_data.unwrap() - }; - - let from_tx = match aux.copy_details() { - CopyDetails::TxCallData(root_call) => root_call, - _ => unreachable!("the source has to come from calldata and not code"), - }; - - self.src_addr - .assign(region, offset, Some(F::from(aux.src_addr())))?; - self.dst_addr - .assign(region, offset, Some(F::from(aux.dst_addr())))?; - self.bytes_left - .assign(region, offset, Some(F::from(aux.bytes_left())))?; - self.src_addr_end - .assign(region, offset, Some(F::from(aux.src_addr_end())))?; - self.from_tx - .assign(region, offset, Some(F::from(from_tx as u64)))?; - let src_id = if call.is_root { tx.id } else { call.caller_id }; - self.src_id - .assign(region, offset, Some(F::from(src_id as u64)))?; - - // Fill in selectors and bytes - let mut rw_idx = 0; - let mut bytes = vec![0u8; MAX_COPY_BYTES]; - let mut selectors = vec![false; MAX_COPY_BYTES]; - for idx in 0..std::cmp::min(aux.bytes_left() as usize, MAX_COPY_BYTES) { - let src_addr = aux.src_addr() as usize + idx; - selectors[idx] = true; - bytes[idx] = if selectors[idx] && src_addr < aux.src_addr_end() as usize { - if from_tx { - tx.call_data[src_addr] - } else { - rw_idx += 1; - block.rws[step.rw_indices[rw_idx]].memory_value() - } - } else { - 0 - }; - // increase rw_idx for writing back to memory - rw_idx += 1 - } - - self.buffer_reader.assign( - region, - offset, - aux.src_addr(), - aux.src_addr_end(), - &bytes, - &selectors, - )?; - - let num_bytes_copied = std::cmp::min(aux.bytes_left(), MAX_COPY_BYTES as u64); - self.finish_gadget.assign( - region, - offset, - F::from(num_bytes_copied), - F::from(aux.bytes_left()), - )?; - - Ok(()) - } -} - -#[cfg(test)] -pub mod test { - use crate::{ - evm_circuit::{ - execution::memory_copy::MAX_COPY_BYTES, - step::ExecutionState, - test::{rand_bytes, run_test_circuit_incomplete_fixed_table}, - witness::{Block, Bytecode, Call, ExecStep, Rw, RwMap, Transaction}, - }, - table::RwTableTag, - }; - use bus_mapping::circuit_input_builder::{CopyDetails, StepAuxiliaryData}; - use eth_types::evm_types::OpcodeId; - use halo2_proofs::arithmetic::BaseExt; - use halo2_proofs::pairing::bn256::Fr; - use std::collections::HashMap; - - pub(crate) const CALL_ID: usize = 1; - pub(crate) const CALLER_ID: usize = 0; - pub(crate) const TX_ID: usize = 1; - - #[allow(clippy::too_many_arguments)] - fn make_memory_copy_step( - src_addr: u64, - dst_addr: u64, - src_addr_end: u64, - bytes_left: usize, - from_tx: bool, - program_counter: u64, - stack_pointer: usize, - memory_size: u64, - rw_counter: usize, - rws: &mut RwMap, - bytes_map: &HashMap, - ) -> (ExecStep, usize) { - let mut rw_offset: usize = 0; - let memory_rws: &mut Vec<_> = rws.0.entry(RwTableTag::Memory).or_insert_with(Vec::new); - let rw_idx_start = memory_rws.len(); - for idx in 0..std::cmp::min(bytes_left, MAX_COPY_BYTES) { - let addr = src_addr + idx as u64; - let byte = if addr < src_addr_end { - assert!(bytes_map.contains_key(&addr)); - if !from_tx { - memory_rws.push(Rw::Memory { - rw_counter: rw_counter + rw_offset, - is_write: false, - call_id: CALLER_ID, - memory_address: src_addr + idx as u64, - byte: bytes_map[&addr], - }); - rw_offset += 1; - } - bytes_map[&addr] - } else { - 0 - }; - // write to destination memory - memory_rws.push(Rw::Memory { - rw_counter: rw_counter + rw_offset, - is_write: true, - call_id: CALL_ID, - memory_address: dst_addr + idx as u64, - byte, - }); - rw_offset += 1; - } - let rw_idx_end = rws.0[&RwTableTag::Memory].len(); - let aux_data = StepAuxiliaryData::new( - src_addr, - dst_addr, - bytes_left as u64, - src_addr_end, - CopyDetails::TxCallData(from_tx), - ); - let step = ExecStep { - execution_state: ExecutionState::CopyToMemory, - rw_indices: (rw_idx_start..rw_idx_end) - .map(|idx| (RwTableTag::Memory, idx)) - .collect(), - rw_counter, - program_counter, - stack_pointer, - memory_size, - gas_cost: 0, - aux_data: Some(aux_data), - ..Default::default() - }; - (step, rw_offset) - } - - #[allow(clippy::too_many_arguments)] - pub(crate) fn make_memory_copy_steps( - buffer: &[u8], - buffer_addr: u64, // buffer base address, use 0 for tx calldata - src_addr: u64, - dst_addr: u64, - length: usize, - from_tx: bool, - program_counter: u64, - stack_pointer: usize, - memory_size: u64, - rw_counter: &mut usize, - rws: &mut RwMap, - steps: &mut Vec, - ) { - let buffer_addr_end = buffer_addr + buffer.len() as u64; - let bytes_map = (buffer_addr..buffer_addr_end) - .zip(buffer.iter().copied()) - .collect(); - - let mut copied = 0; - while copied < length { - let (step, rw_offset) = make_memory_copy_step( - src_addr + copied as u64, - dst_addr + copied as u64, - buffer_addr_end, - length - copied, - from_tx, - program_counter, - stack_pointer, - memory_size, - *rw_counter, - rws, - &bytes_map, - ); - steps.push(step); - *rw_counter += rw_offset; - copied += MAX_COPY_BYTES; - } - } - - fn test_ok_from_memory(src_addr: u64, dst_addr: u64, src_addr_end: u64, length: usize) { - let randomness = Fr::rand(); - let bytecode = Bytecode::new(vec![OpcodeId::RETURN.as_u8()]); - let mut rws = RwMap(Default::default()); - let mut rw_counter = 1; - let mut steps = Vec::new(); - let buffer = rand_bytes((src_addr_end - src_addr) as usize); - let memory_size = (dst_addr + length as u64 + 31) / 32 * 32; - - make_memory_copy_steps( - &buffer, - src_addr, - src_addr, - dst_addr, - length, - false, - 0, - 1024, - memory_size, - &mut rw_counter, - &mut rws, - &mut steps, - ); - - steps.push(ExecStep { - execution_state: ExecutionState::RETURN, - rw_counter, - program_counter: 0, - stack_pointer: 1024, - memory_size, - opcode: Some(OpcodeId::RETURN), - ..Default::default() - }); - - let block = Block { - randomness, - txs: vec![Transaction { - id: TX_ID, - calls: vec![Call { - id: CALL_ID, - is_root: false, - is_create: false, - code_hash: bytecode.hash, - caller_id: CALLER_ID, - ..Default::default() - }], - steps, - ..Default::default() - }], - rws, - bytecodes: HashMap::from_iter([(bytecode.hash, bytecode)]), - ..Default::default() - }; - assert_eq!(run_test_circuit_incomplete_fixed_table(block), Ok(())); - } - - fn test_ok_from_tx(calldata_length: usize, src_addr: u64, dst_addr: u64, length: usize) { - let randomness = Fr::rand(); - let bytecode = Bytecode::new(vec![OpcodeId::RETURN.as_u8(), OpcodeId::RETURN.as_u8()]); - let mut rws = RwMap(Default::default()); - let mut rw_counter = 1; - let calldata: Vec = rand_bytes(calldata_length); - let mut steps = Vec::new(); - let memory_size = (dst_addr + length as u64 + 31) / 32 * 32; - - make_memory_copy_steps( - &calldata, - 0, - src_addr, - dst_addr, - length, - true, - 0, - 1024, - memory_size, - &mut rw_counter, - &mut rws, - &mut steps, - ); - - steps.push(ExecStep { - execution_state: ExecutionState::RETURN, - rw_counter, - program_counter: 0, - stack_pointer: 1024, - memory_size, - opcode: Some(OpcodeId::RETURN), - ..Default::default() - }); - - let block = Block { - randomness, - txs: vec![Transaction { - id: TX_ID, - call_data: calldata, - call_data_length: calldata_length, - calls: vec![Call { - id: CALL_ID, - is_root: true, - is_create: false, - code_hash: bytecode.hash, - ..Default::default() - }], - steps, - ..Default::default() - }], - rws, - bytecodes: HashMap::from_iter([(bytecode.hash, bytecode)]), - ..Default::default() - }; - assert_eq!(run_test_circuit_incomplete_fixed_table(block), Ok(())); - } - - #[test] - fn copy_to_memory_simple() { - test_ok_from_memory(0x40, 0xA0, 0x70, 5); - test_ok_from_tx(32, 5, 0x40, 5); - } - - #[test] - fn copy_to_memory_multi_step() { - test_ok_from_memory(0x20, 0xA0, 0x80, 80); - test_ok_from_tx(128, 10, 0x40, 90); - } - - #[test] - fn copy_to_memory_out_of_bound() { - test_ok_from_memory(0x40, 0xA0, 0x60, 45); - test_ok_from_tx(32, 5, 0x40, 45); - test_ok_from_tx(32, 40, 0x40, 5); - } -} diff --git a/zkevm-circuits/src/evm_circuit/util.rs b/zkevm-circuits/src/evm_circuit/util.rs index 0a2f14aeb6..c7f06fae85 100644 --- a/zkevm-circuits/src/evm_circuit/util.rs +++ b/zkevm-circuits/src/evm_circuit/util.rs @@ -407,11 +407,6 @@ pub(crate) mod rlc { rlc } - // pub(crate) fn value(values: &[u8], randomness: F) -> F { - // values.iter().rev().fold(F::zero(), |acc, value| { - // acc * randomness + F::from(*value as u64) - // }) - // } pub(crate) fn value<'a, F: FieldExt, I>(values: I, randomness: F) -> F where I: IntoIterator, diff --git a/zkevm-circuits/src/evm_circuit/witness.rs b/zkevm-circuits/src/evm_circuit/witness.rs index 25b0b7ba06..b658d04462 100644 --- a/zkevm-circuits/src/evm_circuit/witness.rs +++ b/zkevm-circuits/src/evm_circuit/witness.rs @@ -1207,10 +1207,6 @@ impl From<&circuit_input_builder::ExecStep> for ExecutionState { OpcodeId::DIFFICULTY | OpcodeId::BASEFEE => ExecutionState::BLOCKCTXU256, OpcodeId::GAS => ExecutionState::GAS, OpcodeId::SELFBALANCE => ExecutionState::SELFBALANCE, - OpcodeId::SHA3 => { - log::warn!("ExecutionState::SHA3 is implemented with DummyGadget"); - ExecutionState::SHA3 - } OpcodeId::SHR => ExecutionState::SHR, OpcodeId::SLOAD => ExecutionState::SLOAD, OpcodeId::SSTORE => ExecutionState::SSTORE, @@ -1225,6 +1221,7 @@ impl From<&circuit_input_builder::ExecStep> for ExecutionState { OpcodeId::CODESIZE => ExecutionState::CODESIZE, OpcodeId::RETURN | OpcodeId::REVERT => ExecutionState::RETURN, // dummy ops + OpcodeId::SHA3 => dummy!(ExecutionState::SHA3), OpcodeId::ADDRESS => dummy!(ExecutionState::ADDRESS), OpcodeId::BALANCE => dummy!(ExecutionState::BALANCE), OpcodeId::BLOCKHASH => dummy!(ExecutionState::BLOCKHASH), diff --git a/zkevm-circuits/src/super_circuit.rs b/zkevm-circuits/src/super_circuit.rs index cd1d29afb0..810f2e56a7 100644 --- a/zkevm-circuits/src/super_circuit.rs +++ b/zkevm-circuits/src/super_circuit.rs @@ -19,9 +19,9 @@ //! //! And the following shared tables, with the circuits that use them: //! -//! - [ ] Copy Table +//! - [x] Copy Table //! - [ ] Copy Circuit -//! - [ ] EVM Circuit +//! - [x] EVM Circuit //! - [ ] Rw Table //! - [ ] State Circuit //! - [ ] EVM Circuit @@ -55,10 +55,7 @@ use crate::bytecode_circuit::bytecode_unroller::{ }; use crate::evm_circuit::{table::FixedTableTag, witness::Block, EvmCircuit}; -use crate::table::{ - load_block, load_copy, load_keccaks, load_rws, BlockTable, BytecodeTable, CopyTable, - KeccakTable, RwTable, TxTable, -}; +use crate::table::{BlockTable, BytecodeTable, CopyTable, KeccakTable, RwTable, TxTable}; use crate::util::power_of_randomness_from_instance; use eth_types::Field; use halo2_proofs::{ @@ -167,36 +164,15 @@ impl Circuit .evm_circuit .load_fixed_table(&mut layouter, self.fixed_table_tags.clone())?; config.evm_circuit.load_byte_table(&mut layouter)?; - // load_txs( - // &config.tx_table, - // &mut layouter, - // &self.block.txs, - // self.block.randomness, - // )?; - load_rws( - &config.rw_table, - &mut layouter, - &self.block.rws, - self.block.randomness, - )?; - // load_bytecodes( - // &config.bytecode_table, - // &mut layouter, - // &self.block.bytecodes, - // self.block.randomness, - // )?; - load_block( - &config.block_table, - &mut layouter, - &self.block.context, - self.block.randomness, - )?; - load_copy( - &config.copy_table, - &mut layouter, - &self.block, - self.block.randomness, - )?; + config + .rw_table + .load(&mut layouter, &self.block.rws, self.block.randomness)?; + config + .block_table + .load(&mut layouter, &self.block.context, self.block.randomness)?; + config + .copy_table + .load(&mut layouter, &self.block, self.block.randomness)?; config .evm_circuit .assign_block(&mut layouter, &self.block)?; @@ -228,8 +204,7 @@ impl Circuit keccak_inputs.push(bytecode.bytes.clone()); } // Load Keccak Table - load_keccaks( - &config.keccak_table, + config.keccak_table.load( &mut layouter, keccak_inputs.iter().map(|b| b.as_slice()), self.block.randomness, @@ -342,7 +317,6 @@ mod super_circuit_tests { block, fixed_table_tags, tx_circuit, - // bytecode_size: 2usize.pow(k), bytecode_size: bytecodes_len + 64, }; let prover = MockProver::::run(k, &circuit, instance).unwrap(); @@ -364,10 +338,12 @@ mod super_circuit_tests { } // High memory usage test. Run in serial with: - // `cargo test [...] serial_ -- --ignored --test-threads 1` + // `cargo test [...] skip_ -- --ignored --test-threads 1` + // NOTE: This test is not run as part of CI because it requires more memory than + // is available in github workers and so it gets killed before completion. #[ignore] #[test] - fn serial_test_super_circuit() { + fn skip_test_super_circuit() { let mut rng = ChaCha20Rng::seed_from_u64(2); let chain_id = (*MOCK_CHAIN_ID).as_u64(); @@ -385,7 +361,6 @@ mod super_circuit_tests { let mut wallets = HashMap::new(); wallets.insert(wallet_a.address(), wallet_a); - // Create a custom tx setting Gas to let mut block: GethData = TestContext::<2, 1>::new( None, |accs| { diff --git a/zkevm-circuits/src/table.rs b/zkevm-circuits/src/table.rs index 69f99ac0b0..0a76981335 100644 --- a/zkevm-circuits/src/table.rs +++ b/zkevm-circuits/src/table.rs @@ -1,8 +1,5 @@ //! Table definitions used cross-circuits -// CHANGELOG: Move table definitions from evm_circuit/table.rs and rw_table.rs -// to here - use crate::copy_circuit::number_or_hash_to_field; use crate::evm_circuit::witness::RwRow; use crate::evm_circuit::{ @@ -112,6 +109,47 @@ impl TxTable { value: meta.advice_column(), } } + + /// Assign the `TxTable` from a list of block `Transaction`s, followig the + /// same layout that the Tx Circuit uses. + pub fn load( + &self, + layouter: &mut impl Layouter, + txs: &[Transaction], + randomness: F, + ) -> Result<(), Error> { + layouter.assign_region( + || "tx table", + |mut region| { + let mut offset = 0; + for column in self.columns() { + region.assign_advice( + || "tx table all-zero row", + column, + offset, + || Ok(F::zero()), + )?; + } + offset += 1; + + let tx_table_columns = self.columns(); + for tx in txs.iter() { + for row in tx.table_assignments(randomness) { + for (column, value) in tx_table_columns.iter().zip_eq(row) { + region.assign_advice( + || format!("tx table row {}", offset), + *column, + offset, + || Ok(value), + )?; + } + offset += 1; + } + } + Ok(()) + }, + ) + } } impl TableColumns for TxTable { @@ -120,51 +158,6 @@ impl TableColumns for TxTable { } } -/// Assign the `TxTable` from a list of block `Transaction`s, followig the same -/// layout that the Tx Circuit uses. -pub fn load_txs( - tx_table: &TxTable, - layouter: &mut impl Layouter, - txs: &[Transaction], - randomness: F, -) -> Result<(), Error> { - layouter.assign_region( - || "tx table", - |mut region| { - let mut offset = 0; - for column in tx_table.columns() { - region.assign_advice( - || "tx table all-zero row", - column, - offset, - || Ok(F::zero()), - )?; - } - offset += 1; - - // println!("DBG load_txs"); - let tx_table_columns = tx_table.columns(); - for tx in txs.iter() { - for row in tx.table_assignments(randomness) { - // print!("{:02} ", offset); - for (column, value) in tx_table_columns.iter().zip_eq(row) { - // print!("{:?} ", value); - region.assign_advice( - || format!("tx table row {}", offset), - *column, - offset, - || Ok(value), - )?; - } - offset += 1; - // println!(""); - } - } - Ok(()) - }, - ) -} - /// Tag to identify the operation type in a RwTable row #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, EnumIter)] pub enum RwTableTag { @@ -396,41 +389,41 @@ impl RwTable { } Ok(()) } -} -/// Assign the `RwTable` from a `RwMap`, followig the same -/// table layout that the State Circuit uses. -pub fn load_rws( - rw_table: &RwTable, - layouter: &mut impl Layouter, - rws: &RwMap, - randomness: F, -) -> Result<(), Error> { - layouter.assign_region( - || "rw table", - |mut region| { - let mut offset = 0; - rw_table.assign(&mut region, offset, &Default::default())?; - offset += 1; - - let mut rows = rws - .0 - .values() - .flat_map(|rws| rws.iter()) - .collect::>(); - - rows.sort_by_key(|a| a.rw_counter()); - let mut expected_rw_counter = 1; - for rw in rows { - assert!(rw.rw_counter() == expected_rw_counter); - expected_rw_counter += 1; - - rw_table.assign(&mut region, offset, &rw.table_assignment(randomness))?; + /// Assign the `RwTable` from a `RwMap`, followig the same + /// table layout that the State Circuit uses. + pub fn load( + &self, + layouter: &mut impl Layouter, + rws: &RwMap, + randomness: F, + ) -> Result<(), Error> { + layouter.assign_region( + || "rw table", + |mut region| { + let mut offset = 0; + self.assign(&mut region, offset, &Default::default())?; offset += 1; - } - Ok(()) - }, - ) + + let mut rows = rws + .0 + .values() + .flat_map(|rws| rws.iter()) + .collect::>(); + + rows.sort_by_key(|a| a.rw_counter()); + let mut expected_rw_counter = 1; + for rw in rows { + assert!(rw.rw_counter() == expected_rw_counter); + expected_rw_counter += 1; + + self.assign(&mut region, offset, &rw.table_assignment(randomness))?; + offset += 1; + } + Ok(()) + }, + ) + } } /// Tag to identify the field in a Bytecode Table row @@ -445,13 +438,11 @@ pub enum BytecodeFieldTag { } impl_expr!(BytecodeFieldTag); -// CHANGELOG: Added BytecodeTable to help reusing the table config with other -// circuits /// Table with Bytecode indexed by its Code Hash #[derive(Clone, Debug)] pub struct BytecodeTable { /// Code Hash - pub code_hash: Column, // CHANGELOG: Renamed from hash + pub code_hash: Column, /// Tag pub tag: Column, /// Index @@ -473,6 +464,47 @@ impl BytecodeTable { value: meta.advice_column(), } } + + /// Assign the `BytecodeTable` from a list of bytecodes, followig the same + /// table layout that the Bytecode Circuit uses. + pub fn load<'a, F: Field>( + &self, + layouter: &mut impl Layouter, + bytecodes: impl IntoIterator + Clone, + randomness: F, + ) -> Result<(), Error> { + layouter.assign_region( + || "bytecode table", + |mut region| { + let mut offset = 0; + for column in self.columns() { + region.assign_advice( + || "bytecode table all-zero row", + column, + offset, + || Ok(F::zero()), + )?; + } + offset += 1; + + let bytecode_table_columns = self.columns(); + for bytecode in bytecodes.clone() { + for row in bytecode.table_assignments(randomness) { + for (column, value) in bytecode_table_columns.iter().zip_eq(row) { + region.assign_advice( + || format!("bytecode table row {}", offset), + *column, + offset, + || Ok(value), + )?; + } + offset += 1; + } + } + Ok(()) + }, + ) + } } impl TableColumns for BytecodeTable { @@ -487,56 +519,6 @@ impl TableColumns for BytecodeTable { } } -// use crate::util::TableShow; - -/// Assign the `BytecodeTable` from a list of bytecodes, followig the same -/// table layout that the Bytecode Circuit uses. -pub fn load_bytecodes<'a, F: Field>( - bytecode_table: &BytecodeTable, - layouter: &mut impl Layouter, - bytecodes: impl IntoIterator + Clone, - randomness: F, -) -> Result<(), Error> { - // println!("> load_bytecodes"); - // let mut table = TableShow::::new(vec!["codeHash", "tag", "index", - // "isCode", "value"]); - layouter.assign_region( - || "bytecode table", - |mut region| { - let mut offset = 0; - for column in bytecode_table.columns() { - region.assign_advice( - || "bytecode table all-zero row", - column, - offset, - || Ok(F::zero()), - )?; - } - offset += 1; - - let bytecode_table_columns = bytecode_table.columns(); - for bytecode in bytecodes.clone() { - for row in bytecode.table_assignments(randomness) { - // let mut column_index = 0; - for (column, value) in bytecode_table_columns.iter().zip_eq(row) { - region.assign_advice( - || format!("bytecode table row {}", offset), - *column, - offset, - || Ok(value), - )?; - // table.push(column_index, value); - // column_index += 1; - } - offset += 1; - } - } - // table.print(); - Ok(()) - }, - ) -} - /// Tag to identify the field in a Block Table row // Keep the sequence consistent with OpcodeId for scalar #[derive(Clone, Copy, Debug)] @@ -581,51 +563,51 @@ impl BlockTable { value: meta.advice_column(), } } -} - -impl TableColumns for BlockTable { - fn columns(&self) -> Vec> { - vec![self.tag, self.index, self.value] - } -} -/// Assign the `BlockTable` from a `BlockContext`. -pub fn load_block( - block_table: &BlockTable, - layouter: &mut impl Layouter, - block: &BlockContext, - randomness: F, -) -> Result<(), Error> { - layouter.assign_region( - || "block table", - |mut region| { - let mut offset = 0; - for column in block_table.columns() { - region.assign_advice( - || "block table all-zero row", - column, - offset, - || Ok(F::zero()), - )?; - } - offset += 1; - - let block_table_columns = block_table.columns(); - for row in block.table_assignments(randomness) { - for (column, value) in block_table_columns.iter().zip_eq(row) { + /// Assign the `BlockTable` from a `BlockContext`. + pub fn load( + &self, + layouter: &mut impl Layouter, + block: &BlockContext, + randomness: F, + ) -> Result<(), Error> { + layouter.assign_region( + || "block table", + |mut region| { + let mut offset = 0; + for column in self.columns() { region.assign_advice( - || format!("block table row {}", offset), - *column, + || "block table all-zero row", + column, offset, - || Ok(value), + || Ok(F::zero()), )?; } offset += 1; - } - Ok(()) - }, - ) + let block_table_columns = self.columns(); + for row in block.table_assignments(randomness) { + for (column, value) in block_table_columns.iter().zip_eq(row) { + region.assign_advice( + || format!("block table row {}", offset), + *column, + offset, + || Ok(value), + )?; + } + offset += 1; + } + + Ok(()) + }, + ) + } +} + +impl TableColumns for BlockTable { + fn columns(&self) -> Vec> { + vec![self.tag, self.index, self.value] + } } /// Keccak Table, used to verify keccak hashing from RLC'ed input. @@ -651,6 +633,67 @@ impl KeccakTable { output_rlc: meta.advice_column(), } } + + /// Generate the keccak table assignments from a byte array input. + pub fn assignments(input: &[u8], randomness: F) -> Vec<[F; 4]> { + let input_rlc: F = rlc::value(input.iter().rev(), randomness); + let input_len = F::from(input.len() as u64); + let mut keccak = Keccak::default(); + keccak.update(input); + let output = keccak.digest(); + let output_rlc = RandomLinearCombination::::random_linear_combine( + Word::from_big_endian(output.as_slice()).to_le_bytes(), + randomness, + ); + + vec![[F::one(), input_rlc, input_len, output_rlc]] + } + + // NOTE: For now, the input_rlc of the keccak is defined as + // `RLC(reversed(input))` for convenience of the circuits that do the lookups. + // This allows calculating the `input_rlc` after all the inputs bytes have been + // layed out via the pattern `acc[i] = acc[i-1] * r + value[i]`. + /// Assign the `KeccakTable` from a list hashing inputs, followig the same + /// table layout that the Keccak Circuit uses. + pub fn load<'a, F: Field>( + &self, + layouter: &mut impl Layouter, + inputs: impl IntoIterator + Clone, + randomness: F, + ) -> Result<(), Error> { + layouter.assign_region( + || "keccak table", + |mut region| { + let mut offset = 0; + for column in self.columns() { + region.assign_advice( + || "keccak table all-zero row", + column, + offset, + || Ok(F::zero()), + )?; + } + offset += 1; + + let keccak_table_columns = self.columns(); + for input in inputs.clone() { + for row in Self::assignments(input, randomness) { + // let mut column_index = 0; + for (column, value) in keccak_table_columns.iter().zip_eq(row) { + region.assign_advice( + || format!("keccak table row {}", offset), + *column, + offset, + || Ok(value), + )?; + } + offset += 1; + } + } + Ok(()) + }, + ) + } } impl TableColumns for KeccakTable { @@ -664,75 +707,6 @@ impl TableColumns for KeccakTable { } } -/// Generate the keccak table assignments from a byte array input. -pub fn keccak_table_assignments(input: &[u8], randomness: F) -> Vec<[F; 4]> { - // CHANGELOG: Using `RLC(reversed(input))` - let input_rlc: F = rlc::value(input.iter().rev(), randomness); - let input_len = F::from(input.len() as u64); - let mut keccak = Keccak::default(); - keccak.update(input); - let output = keccak.digest(); - let output_rlc = RandomLinearCombination::::random_linear_combine( - Word::from_big_endian(output.as_slice()).to_le_bytes(), - randomness, - ); - - vec![[F::one(), input_rlc, input_len, output_rlc]] -} - -// NOTE: For now, the input_rlc of the keccak is defined as -// `RLC(reversed(input))` for convenience of the circuits that do the lookups. -// This allows calculating the `input_rlc` after all the inputs bytes have been -// layed out via the pattern `acc[i] = acc[i-1] * r + value[i]`. -/// Assign the `KeccakTable` from a list hashing inputs, followig the same -/// table layout that the Keccak Circuit uses. -pub fn load_keccaks<'a, F: Field>( - keccak_table: &KeccakTable, - layouter: &mut impl Layouter, - inputs: impl IntoIterator + Clone, - randomness: F, -) -> Result<(), Error> { - // println!("> super_circuit.load_keccaks"); - // let mut table = TableShow::::new(vec!["is_enabled", "input_rlc", - // "input_len", "output_rlc"]); - layouter.assign_region( - || "keccak table", - |mut region| { - let mut offset = 0; - for column in keccak_table.columns() { - region.assign_advice( - || "keccak table all-zero row", - column, - offset, - || Ok(F::zero()), - )?; - } - offset += 1; - - let keccak_table_columns = keccak_table.columns(); - for input in inputs.clone() { - // println!("+ {:?}", input); - for row in keccak_table_assignments(input, randomness) { - // let mut column_index = 0; - for (column, value) in keccak_table_columns.iter().zip_eq(row) { - region.assign_advice( - || format!("keccak table row {}", offset), - *column, - offset, - || Ok(value), - )?; - // table.push(column_index, value); - // column_index += 1; - } - offset += 1; - } - } - // table.print(); - Ok(()) - }, - ) -} - /// Copy Table, used to verify copies of byte chunks between Memory, Bytecode, /// TxLogs and TxCallData. #[derive(Clone, Copy, Debug)] @@ -777,6 +751,94 @@ impl CopyTable { rwc_inc_left: meta.advice_column(), } } + + /// Generate the keccak table assignments from a byte array input. + pub fn assignments( + copy_event: &CopyEvent, + randomness: F, + ) -> Vec<(CopyDataType, [F; 7])> { + let mut assignments = Vec::new(); + for (step_idx, copy_step) in copy_event.steps.iter().enumerate() { + // is_first + let is_first = if step_idx == 0 { F::one() } else { F::zero() }; + // id + let id = { + let id = if copy_step.rw.is_read() { + ©_event.src_id + } else { + ©_event.dst_id + }; + number_or_hash_to_field(id, randomness) + }; + // addr + let addr = match copy_step.tag { + CopyDataType::TxLog => { + let addr = (U256::from(copy_step.addr) + + (U256::from(TxLogFieldTag::Data as u64) << 32) + + (U256::from(copy_event.log_id.unwrap()) << 48)) + .to_address(); + addr.to_scalar().unwrap() + } + _ => F::from(copy_step.addr), + }; + assignments.push(( + copy_step.tag, + [ + is_first, + id, + addr, + F::from(copy_event.src_addr_end), // src_addr_end + F::from(copy_event.length - step_idx as u64 / 2), // bytes_left + F::from(copy_step.rwc.0 as u64), // rw_counter + F::from(copy_step.rwc_inc_left), // rw_inc_left + ], + )); + } + assignments + } + + /// Assign the `CopyTable` from a `Block`. + pub fn load( + &self, + layouter: &mut impl Layouter, + block: &Block, + randomness: F, + ) -> Result<(), Error> { + layouter.assign_region( + || "copy table", + |mut region| { + let mut offset = 0; + for column in self.columns() { + region.assign_advice( + || "copy table all-zero row", + column, + offset, + || Ok(F::zero()), + )?; + } + offset += 1; + + let tag_chip = BinaryNumberChip::construct(self.tag); + let copy_table_columns = self.columns(); + for copy_event in block.copy_events.values() { + for (tag, row) in Self::assignments(copy_event, randomness) { + for (column, value) in copy_table_columns.iter().zip_eq(row) { + region.assign_advice( + || format!("copy table row {}", offset), + *column, + offset, + || Ok(value), + )?; + } + tag_chip.assign(&mut region, offset, &tag)?; + offset += 1; + } + } + + Ok(()) + }, + ) + } } impl CopyTable { @@ -810,91 +872,3 @@ impl LookupTable for CopyTable { ] } } - -/// Generate the keccak table assignments from a byte array input. -pub fn copy_table_assignments( - copy_event: &CopyEvent, - randomness: F, -) -> Vec<(CopyDataType, [F; 7])> { - let mut assignments = Vec::new(); - for (step_idx, copy_step) in copy_event.steps.iter().enumerate() { - // is_first - let is_first = if step_idx == 0 { F::one() } else { F::zero() }; - // id - let id = { - let id = if copy_step.rw.is_read() { - ©_event.src_id - } else { - ©_event.dst_id - }; - number_or_hash_to_field(id, randomness) - }; - // addr - let addr = match copy_step.tag { - CopyDataType::TxLog => { - let addr = (U256::from(copy_step.addr) - + (U256::from(TxLogFieldTag::Data as u64) << 32) - + (U256::from(copy_event.log_id.unwrap()) << 48)) - .to_address(); - addr.to_scalar().unwrap() - } - _ => F::from(copy_step.addr), - }; - assignments.push(( - copy_step.tag, - [ - is_first, - id, - addr, - F::from(copy_event.src_addr_end), // src_addr_end - F::from(copy_event.length - step_idx as u64 / 2), // bytes_left - F::from(copy_step.rwc.0 as u64), // rw_counter - F::from(copy_step.rwc_inc_left), // rw_inc_left - ], - )); - } - assignments -} - -/// Assign the `CopyTable` from a `Block`. -pub fn load_copy( - copy_table: &CopyTable, - layouter: &mut impl Layouter, - block: &Block, - randomness: F, -) -> Result<(), Error> { - layouter.assign_region( - || "copy table", - |mut region| { - let mut offset = 0; - for column in copy_table.columns() { - region.assign_advice( - || "copy table all-zero row", - column, - offset, - || Ok(F::zero()), - )?; - } - offset += 1; - - let tag_chip = BinaryNumberChip::construct(copy_table.tag); - let copy_table_columns = copy_table.columns(); - for copy_event in block.copy_events.values() { - for (tag, row) in copy_table_assignments(copy_event, randomness) { - for (column, value) in copy_table_columns.iter().zip_eq(row) { - region.assign_advice( - || format!("copy table row {}", offset), - *column, - offset, - || Ok(value), - )?; - } - tag_chip.assign(&mut region, offset, &tag)?; - offset += 1; - } - } - - Ok(()) - }, - ) -} diff --git a/zkevm-circuits/src/tx_circuit.rs b/zkevm-circuits/src/tx_circuit.rs index 2797d132a9..642330cd6b 100644 --- a/zkevm-circuits/src/tx_circuit.rs +++ b/zkevm-circuits/src/tx_circuit.rs @@ -4,11 +4,9 @@ // - *_be: Big-Endian bytes // - *_le: Little-Endian bytes -#![allow(missing_docs)] - pub mod sign_verify; -use crate::table::{load_keccaks, KeccakTable, TxFieldTag, TxTable}; +use crate::table::{KeccakTable, TxFieldTag, TxTable}; use crate::util::{power_of_randomness_from_instance, random_linear_combine_word as rlc}; use eth_types::{ geth_types::Transaction, Address, Field, ToBigEndian, ToLittleEndian, ToScalar, Word, @@ -88,6 +86,7 @@ fn ct_option_ok_or(v: CtOption, err: E) -> Result { Option::::from(v).ok_or(err) } +/// Return all the keccak inputs that the Tx Circuit requires. pub fn keccak_inputs(txs: &[Transaction], chain_id: u64) -> Result>, Error> { let mut inputs = Vec::new(); let sign_datas: Vec = txs @@ -164,6 +163,7 @@ pub struct TxCircuitConfig { } impl TxCircuitConfig { + /// Return a new TxCircuitConfig pub fn new( meta: &mut ConstraintSystem, power_of_randomness: [Expression; sign_verify::POW_RAND_SIZE], @@ -223,6 +223,7 @@ pub struct TxCircuit impl TxCircuit { + /// Return a new TxCircuit pub fn new( aux_generator: Secp256k1Affine, randomness: F, @@ -241,6 +242,7 @@ impl } } + /// Make the assignments to the TxCircuit pub fn assign( &self, config: &TxCircuitConfig, @@ -280,7 +282,6 @@ impl let address_cell = assigned_sig_verif.address.cell(); let msg_hash_rlc_cell = assigned_sig_verif.msg_hash_rlc.cell(); let msg_hash_rlc_value = assigned_sig_verif.msg_hash_rlc.value(); - // println!("DBG tx_circuit.assign"); for (tag, value) in &[ ( TxFieldTag::Nonce, @@ -327,14 +328,6 @@ impl ] { let assigned_cell = config.assign_row(&mut region, offset, i + 1, *tag, 0, *value)?; - // println!( - // "{:02} {:?} {:?} {:?} {:?}", - // offset, - // i + 1, - // *tag as u64, - // 0, - // *value - // ); offset += 1; // Ref. spec 0. Copy constraints using fixed offsets between the tx rows and @@ -415,8 +408,7 @@ impl Circuit mut layouter: impl Layouter, ) -> Result<(), Error> { self.assign(&config, &mut layouter)?; - load_keccaks( - &config.keccak_table, + config.keccak_table.load( &mut layouter, keccak_inputs(&self.txs, self.chain_id)? .iter() diff --git a/zkevm-circuits/src/tx_circuit/sign_verify.rs b/zkevm-circuits/src/tx_circuit/sign_verify.rs index 65d417599e..4eb2bded7d 100644 --- a/zkevm-circuits/src/tx_circuit/sign_verify.rs +++ b/zkevm-circuits/src/tx_circuit/sign_verify.rs @@ -11,7 +11,7 @@ use crate::{ }; use ecc::{EccConfig, GeneralEccChip}; use ecdsa::ecdsa::{AssignedEcdsaSig, AssignedPublicKey, EcdsaChip}; -use eth_types::{self, Field, ToLittleEndian}; +use eth_types::{self, Field}; use gadgets::is_zero::{IsZeroChip, IsZeroConfig, IsZeroInstruction}; use group::{ff::Field as GroupField, prime::PrimeCurveAffine, Curve}; use halo2_proofs::{ @@ -86,8 +86,6 @@ pub(crate) fn pk_bytes_le(pk: &Secp256k1Affine) -> [u8; 64] { pk_le } -// CHANGELOG: Add function to obtain all the keccak inputs required by the -// SignVerifyChip pub(crate) fn keccak_inputs(sigs: &[SignData]) -> Vec> { let mut inputs = Vec::new(); for sig in sigs { @@ -228,8 +226,6 @@ impl SignVerifyConfig { // Column 3: output_rlc (pk_hash_rlc) let keccak_output_rlc = meta.query_advice(keccak_table.output_rlc, Rotation::cur()); let mut pk_hash_rev = pk_hash.map(|c| meta.query_advice(c, Rotation::cur())); - // CHANGELOG: Reverse the pk_hash used in the lookup so that the RLC is - // calculated as if it was a hash in an Ethereum Word. pk_hash_rev.reverse(); // Ethereum decodes pk_hash into a Word as big endian, but // `random_linear_combine_expr` expects LSB first. let pk_hash_rlc = RandomLinearCombination::random_linear_combine_expr( @@ -298,8 +294,6 @@ pub(crate) struct KeccakAux { output: [u8; 32], } -use crate::util::TableShow; - impl SignVerifyConfig { pub(crate) fn load_range(&self, layouter: &mut impl Layouter) -> Result<(), Error> { let bit_len_lookup = BIT_LEN_LIMB / NUMBER_OF_LOOKUP_LIMBS; @@ -310,83 +304,6 @@ impl SignVerifyConfig { Ok(()) } - fn keccak_assign_row( - &self, - region: &mut Region<'_, F>, - offset: usize, - is_enabled: F, - input_rlc: F, - input_len: usize, - output_rlc: F, - ) -> Result<(), Error> { - for (name, column, value) in &[ - ("is_enabled", self.keccak_table.is_enabled, is_enabled), - ("input_rlc", self.keccak_table.input_rlc, input_rlc), - ( - "input_len", - self.keccak_table.input_len, - F::from(input_len as u64), - ), - ("output_rlc", self.keccak_table.output_rlc, output_rlc), - ] { - region.assign_advice( - || format!("Keccak table assign {} {}", name, offset), - *column, - offset, - || Ok(*value), - )?; - } - Ok(()) - } - - pub(crate) fn load_keccak( - &self, - layouter: &mut impl Layouter, - auxs: Vec, - randomness: F, - ) -> Result<(), Error> { - layouter.assign_region( - || "keccak table", - |mut region| { - let mut offset = 0; - - // All zero row to allow simulating a disabled lookup. - self.keccak_assign_row(&mut region, offset, F::zero(), F::zero(), 0, F::zero())?; - offset += 1; - - println!("> sign_verify.load_keccak"); - let mut table = - TableShow::::new(vec!["is_enabled", "input_rlc", "input_len", "output_rlc"]); - - for aux in &auxs { - let KeccakAux { input, output } = aux; - let input_rlc = - RandomLinearCombination::random_linear_combine(*input, randomness); - let output_rlc = Word::random_linear_combine( - eth_types::Word::from_big_endian(output.as_slice()).to_le_bytes(), - randomness, - ); - self.keccak_assign_row( - &mut region, - offset, - F::one(), - input_rlc, - input.len(), - output_rlc, - )?; - offset += 1; - table.push(0, F::one()); - table.push(1, input_rlc); - table.push(2, F::from(input.len() as u64)); - table.push(3, output_rlc); - } - table.print(); - Ok(()) - }, - )?; - Ok(()) - } - pub(crate) fn ecc_chip_config(&self) -> EccConfig { EccConfig::new(self.range_config.clone(), self.main_gate_config.clone()) } @@ -756,7 +673,6 @@ impl SignVerifyChip { }, )?; - // config.load_keccak(layouter, keccak_auxs, randomness)?; config.load_range(layouter)?; Ok(assigned_sig_verifs) @@ -833,7 +749,7 @@ fn pub_key_hash_to_address(pk_hash: &[u8]) -> F { #[cfg(test)] mod sign_verify_tests { use super::*; - use crate::{table::load_keccaks, util::power_of_randomness_from_instance}; + use crate::util::power_of_randomness_from_instance; use group::Group; use halo2_proofs::{ circuit::SimpleFloorPlanner, dev::MockProver, pairing::bn256::Fr, plonk::Circuit, @@ -887,8 +803,7 @@ mod sign_verify_tests { self.randomness, &self.signatures, )?; - load_keccaks( - &config.sign_verify.keccak_table, + config.sign_verify.keccak_table.load( &mut layouter, keccak_inputs(&self.signatures).iter().map(|b| b.as_slice()), self.randomness, diff --git a/zkevm-circuits/src/util.rs b/zkevm-circuits/src/util.rs index ab7ed4905f..5a650be787 100644 --- a/zkevm-circuits/src/util.rs +++ b/zkevm-circuits/src/util.rs @@ -11,72 +11,9 @@ pub(crate) fn random_linear_combine_word(bytes: [u8; 32], randomness: crate::evm_circuit::util::Word::random_linear_combine(bytes, randomness) } -use itertools::Itertools; - -/// TODO -pub struct TableShow { - names: Vec, - columns: Vec>, -} - -impl TableShow { - /// TODO - pub fn new(names: Vec<&str>) -> Self { - let names_len = names.len(); - Self { - names: names.iter().map(|s| s.to_string()).collect(), - columns: vec![Vec::new(); names_len], - } - } - - /// TODO - pub fn push(&mut self, column_index: usize, v: F) { - self.columns[column_index].push(v); - } - - /// TODO - pub fn print(&self) { - print!("|"); - for name in &self.names { - print!(" {} |", name) - } - println!("\n---"); - let num_bytes: Vec = self - .columns - .iter() - .map(|col| col.iter().max().unwrap()) - .map(|max| { - let max_repr = max.to_repr(); - let bytes = max_repr.as_ref(); - let mut len = 1; - for i in (0..32).rev() { - if bytes[i] != 0 { - len = i + 1; - break; - } - } - len - }) - .collect(); - for row_index in 0..self.columns[0].len() { - print!("|"); - for (column_index, column) in self.columns.iter().enumerate() { - print!( - " {:02x} |", - column[row_index] - .to_repr() - .as_ref() - .iter() - .take(num_bytes[column_index]) - .format("") - ); - } - println!(); - } - } -} - -/// TODO +/// Query N instances at current rotation and return their expressions. This +/// function is used to get the power of randomness (passed as +/// instances) in our tests. pub fn power_of_randomness_from_instance( meta: &mut ConstraintSystem, ) -> [Expression; N] { From 6d881aaf246fe7086cb724ec18b8ddc75079edd6 Mon Sep 17 00:00:00 2001 From: Eduard S Date: Thu, 21 Jul 2022 12:47:22 +0200 Subject: [PATCH 25/26] Reset our halo2 fork --- Cargo.lock | 17 +---------------- Cargo.toml | 13 +++---------- zkevm-circuits/src/super_circuit.rs | 9 ++------- 3 files changed, 6 insertions(+), 33 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6ced703fef..78db2818cf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1854,19 +1854,15 @@ checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" [[package]] name = "halo2_proofs" version = "0.1.0-beta.1" -source = "git+https://github.com/ed255/halo2.git?branch=feature/dev-tooling#47834696cc62fb4c259c255d713e596b1e24f283" +source = "git+https://github.com/privacy-scaling-explorations/halo2.git?tag=v2022_06_03#1fc67702da729b41bfeebc9764c4c6effbd1f9ad" dependencies = [ "blake2b_simd 1.0.0", "bumpalo", "cfg-if 0.1.10", "ff 0.11.1", "group 0.11.0", - "log", - "num-bigint", - "num-integer", "pairing_bn256", "plotters", - "poseidon", "rand", "rand_core", "rayon", @@ -2903,17 +2899,6 @@ dependencies = [ "miniz_oxide", ] -[[package]] -name = "poseidon" -version = "0.1.0" -source = "git+https://github.com/appliedzkp/poseidon.git?branch=circuit#1f8609776f64f36b518aac1732f18758d65a2791" -dependencies = [ - "group 0.11.0", - "pairing_bn256", - "rand", - "subtle", -] - [[package]] name = "ppv-lite86" version = "0.2.16" diff --git a/Cargo.toml b/Cargo.toml index c9134da0a7..df46afcd53 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,14 +19,7 @@ members = [ # and leads to a compilation error. This can be removed once the upstream PR # is resolved: https://github.com/bitvecto-rs/bitvec/pull/141 bitvec = { git = "https://github.com/ed255/bitvec.git", rev = "5cfc5fa8496c66872d21905e677120fc3e79693c" } -# halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", tag = "v2022_06_03" } -# halo2_proofs = { path = "../halo2/halo2_proofs" } -halo2_proofs = { git = "https://github.com/ed255/halo2.git", branch = "feature/dev-tooling" } - -[patch."https://github.com/privacy-scaling-explorations/halo2"] -# halo2_proofs = { git = "https://github.com/han0110/halo2", branch = "feature/abstraction-experiment", package = "halo2_proofs" } -# halo2_proofs = { path = "../halo2/halo2_proofs" } -halo2_proofs = { git = "https://github.com/ed255/halo2.git", branch = "feature/dev-tooling" } +halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", tag = "v2022_06_03" } # Definition of benchmarks profile to use. [profile.bench] @@ -45,5 +38,5 @@ debug = false debug-assertions = true overflow-checks = true rpath = false -# lto = "thin" # TODO: Uncomment when the PR is ready to review -# incremental = false # TODO: Uncomment when the PR is ready to review +lto = "thin" +incremental = false diff --git a/zkevm-circuits/src/super_circuit.rs b/zkevm-circuits/src/super_circuit.rs index 810f2e56a7..b172fae9e5 100644 --- a/zkevm-circuits/src/super_circuit.rs +++ b/zkevm-circuits/src/super_circuit.rs @@ -259,7 +259,7 @@ mod super_circuit_tests { use ethers_signers::{LocalWallet, Signer}; use group::{Curve, Group}; use halo2_proofs::arithmetic::{CurveAffine, Field as Halo2Field}; - use halo2_proofs::dev::{MockProver, VerifyConfig, VerifyFailure}; + use halo2_proofs::dev::{MockProver, VerifyFailure}; use halo2_proofs::pairing::bn256::Fr; use mock::{TestContext, MOCK_CHAIN_ID}; use rand::SeedableRng; @@ -320,12 +320,7 @@ mod super_circuit_tests { bytecode_size: bytecodes_len + 64, }; let prover = MockProver::::run(k, &circuit, instance).unwrap(); - prover.verify_par(VerifyConfig { - selectors: false, - gates: false, - lookups: true, - perms: false, - }) + prover.verify() } fn run_test_circuit_complete_fixed_table( From 7955480c55c5be39fc7efb1710ca2dbf58e34ec8 Mon Sep 17 00:00:00 2001 From: Eduard S Date: Wed, 27 Jul 2022 17:26:06 +0200 Subject: [PATCH 26/26] Address comments from @han0110 and @lispc --- .../src/bytecode_circuit/bytecode_unroller.rs | 14 +++++--------- zkevm-circuits/src/evm_circuit.rs | 2 +- zkevm-circuits/src/super_circuit.rs | 3 +++ zkevm-circuits/src/table.rs | 18 +++++++++--------- 4 files changed, 18 insertions(+), 19 deletions(-) diff --git a/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs b/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs index cce4384b33..6547582a06 100644 --- a/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs +++ b/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs @@ -2,7 +2,7 @@ use crate::{ evm_circuit::util::{ and, constraint_builder::BaseConstraintBuilder, not, or, select, RandomLinearCombination, }, - table::{BytecodeFieldTag, BytecodeTable, KeccakTable, TableColumns}, + table::{BytecodeFieldTag, BytecodeTable, DynamicTableColumns, KeccakTable}, util::Expr, }; use bus_mapping::evm::OpcodeId; @@ -680,13 +680,7 @@ mod tests { } fn configure(meta: &mut ConstraintSystem) -> Self::Config { - let bytecode_table = BytecodeTable { - code_hash: meta.advice_column(), - tag: meta.advice_column(), - index: meta.advice_column(), - is_code: meta.advice_column(), - value: meta.advice_column(), - }; + let bytecode_table = BytecodeTable::construct(meta); let randomness = power_of_randomness_from_instance::<_, 1>(meta); let keccak_table = KeccakTable::construct(meta); @@ -717,7 +711,9 @@ mod tests { randomness, }; - let instance = vec![vec![randomness; (1 << k) - 7 + 1]]; + let num_rows = 1 << k; + const NUM_BLINDING_ROWS: usize = 7 - 1; + let instance = vec![vec![randomness; num_rows - NUM_BLINDING_ROWS]]; let prover = MockProver::::run(k, &circuit, instance).unwrap(); let err = prover.verify(); let print_failures = true; diff --git a/zkevm-circuits/src/evm_circuit.rs b/zkevm-circuits/src/evm_circuit.rs index eae0ff0470..217af17e7f 100644 --- a/zkevm-circuits/src/evm_circuit.rs +++ b/zkevm-circuits/src/evm_circuit.rs @@ -261,7 +261,7 @@ pub mod test { .load(&mut layouter, &self.block.rws, self.block.randomness)?; config.bytecode_table.load( &mut layouter, - self.block.bytecodes.iter().map(|(_, b)| b), + self.block.bytecodes.values(), self.block.randomness, )?; config diff --git a/zkevm-circuits/src/super_circuit.rs b/zkevm-circuits/src/super_circuit.rs index b172fae9e5..187102ae5b 100644 --- a/zkevm-circuits/src/super_circuit.rs +++ b/zkevm-circuits/src/super_circuit.rs @@ -317,6 +317,9 @@ mod super_circuit_tests { block, fixed_table_tags, tx_circuit, + // Instead of using 1 << k - NUM_BLINDING_ROWS, we use a much smaller number of enabled + // rows for the Bytecode Circuit because otherwise it penalizes significantly the + // MockProver verification time. bytecode_size: bytecodes_len + 64, }; let prover = MockProver::::run(k, &circuit, instance).unwrap(); diff --git a/zkevm-circuits/src/table.rs b/zkevm-circuits/src/table.rs index 0a76981335..d442211c5b 100644 --- a/zkevm-circuits/src/table.rs +++ b/zkevm-circuits/src/table.rs @@ -23,7 +23,7 @@ use strum_macros::{EnumCount, EnumIter}; /// Trait used for dynamic tables. Used to get an automatic implementation of /// the LookupTable trait where each `table_expr` is a query to each column at /// `Rotation::cur`. -pub trait TableColumns { +pub trait DynamicTableColumns { /// Returns the list of advice columns following the table order. fn columns(&self) -> Vec>; } @@ -34,7 +34,7 @@ pub trait LookupTable { fn table_exprs(&self, meta: &mut VirtualCells) -> Vec>; } -impl LookupTable for T { +impl LookupTable for T { fn table_exprs(&self, meta: &mut VirtualCells) -> Vec> { self.columns() .iter() @@ -152,7 +152,7 @@ impl TxTable { } } -impl TableColumns for TxTable { +impl DynamicTableColumns for TxTable { fn columns(&self) -> Vec> { vec![self.tx_id, self.tag, self.index, self.value] } @@ -331,7 +331,7 @@ pub struct RwTable { pub aux2: Column, } -impl TableColumns for RwTable { +impl DynamicTableColumns for RwTable { fn columns(&self) -> Vec> { vec![ self.rw_counter, @@ -507,7 +507,7 @@ impl BytecodeTable { } } -impl TableColumns for BytecodeTable { +impl DynamicTableColumns for BytecodeTable { fn columns(&self) -> Vec> { vec![ self.code_hash, @@ -604,7 +604,7 @@ impl BlockTable { } } -impl TableColumns for BlockTable { +impl DynamicTableColumns for BlockTable { fn columns(&self) -> Vec> { vec![self.tag, self.index, self.value] } @@ -696,7 +696,7 @@ impl KeccakTable { } } -impl TableColumns for KeccakTable { +impl DynamicTableColumns for KeccakTable { fn columns(&self) -> Vec> { vec![ self.is_enabled, @@ -738,7 +738,7 @@ pub struct CopyTable { } impl CopyTable { - /// Construct a new KeccakTable + /// Construct a new CopyTable pub fn construct(meta: &mut ConstraintSystem, q_enable: Column) -> Self { Self { is_first: meta.advice_column(), @@ -752,7 +752,7 @@ impl CopyTable { } } - /// Generate the keccak table assignments from a byte array input. + /// Generate the copy table assignments from a copy event. pub fn assignments( copy_event: &CopyEvent, randomness: F,