diff --git a/gadgets/Cargo.toml b/gadgets/Cargo.toml index be8bf9d550..db57f082d5 100644 --- a/gadgets/Cargo.toml +++ b/gadgets/Cargo.toml @@ -11,6 +11,7 @@ sha3 = "0.7.2" eth-types = { path = "../eth-types" } digest = "0.7.6" strum = "0.24" +itertools = "0.10" [dev-dependencies] rand_xorshift = "0.3" diff --git a/gadgets/src/lib.rs b/gadgets/src/lib.rs index a7150262ee..fea14604d0 100644 --- a/gadgets/src/lib.rs +++ b/gadgets/src/lib.rs @@ -16,6 +16,7 @@ pub mod binary_number; pub mod is_zero; pub mod less_than; pub mod mul_add; +pub mod permutation; pub mod util; use eth_types::Field; diff --git a/zkevm-circuits/src/permutation_circuit.rs b/gadgets/src/permutation.rs similarity index 61% rename from zkevm-circuits/src/permutation_circuit.rs rename to gadgets/src/permutation.rs index f6cb5bfb98..c9c63ad41e 100644 --- a/zkevm-circuits/src/permutation_circuit.rs +++ b/gadgets/src/permutation.rs @@ -1,99 +1,38 @@ +//! Chip that implements permutation fingerprints +//! fingerprints &= \prod_{row_j} \left ( \alpha - \sum_k (\gamma^k \cdot cell_j(k)) \right ) +#[rustfmt::skip] +// | q_row_non_first | alpha | gamma | fingerprints | +// |-----------------|-----------|-----------|-----------------| +// | 0 | alpha | gamma | fingerprints_0 | +// | 1 | alpha | gamma | fingerprints_1 | +// | 1 | alpha | gamma | fingerprints_2 | + use std::marker::PhantomData; +use crate::util::Expr; use eth_types::Field; -use gadgets::util::Expr; use halo2_proofs::{ - circuit::{AssignedCell, Layouter, Region, Value}, - plonk::{Advice, Column, ConstraintSystem, Error, Expression, Instance, Selector}, + circuit::{AssignedCell, Region, Value}, + plonk::{Advice, Column, ConstraintSystem, Error, Expression, Selector}, poly::Rotation, }; use itertools::Itertools; -use crate::{ - util::{Challenges, SubCircuit, SubCircuitConfig}, - witness, -}; - -/// Config for PermutationCircuit +/// Config for PermutationChipConfig #[derive(Clone, Debug)] -pub struct PermutationCircuitConfig { +pub struct PermutationChipConfig { // column fingerprints: Column, alpha: Column, gamma: Column, - permutation_instance: Column, - // selector - q_row_non_first: Selector, // 1 between (first, last], exclude first + q_row_non_first: Selector, // 1 between (first, end], exclude first _phantom: PhantomData, } -/// Circuit configuration arguments -pub struct PermutationCircuitConfigArgs { - pub cols: Vec>, -} - -impl SubCircuitConfig for PermutationCircuitConfig { - type ConfigArgs = PermutationCircuitConfigArgs; - - /// Return a new TxCircuitConfig - fn new(meta: &mut ConstraintSystem, Self::ConfigArgs { cols }: Self::ConfigArgs) -> Self { - let fingerprints = meta.advice_column(); - let permutation_instance = meta.instance_column(); - let alpha = meta.advice_column(); - let gamma = meta.advice_column(); - let q_row_non_first = meta.selector(); - - meta.create_gate("permutation fingerprint update logic", |meta| { - let alpha = meta.query_advice(alpha, Rotation::cur()); - let gamma = meta.query_advice(gamma, Rotation::cur()); - let q_row_non_first = meta.query_selector(q_row_non_first); - let cols_cur_exprs = cols - .iter() - .map(|col| meta.query_advice(*col, Rotation::cur())) - .collect::>>(); - let fingerprint_prev = meta.query_advice(fingerprints, Rotation::prev()); - let fingerprint_cur = meta.query_advice(fingerprints, Rotation::cur()); - - let power_of_gamma = std::iter::successors(1.expr().into(), |prev: &Expression| { - (prev.clone() * gamma.clone()).into() - }) - .take(cols.len()) - .collect::>>(); - - let perf_term = cols_cur_exprs - .iter() - .zip(power_of_gamma.iter()) - .map(|(a, b)| a.clone() * b.clone()) - .fold(0.expr(), |a, b| a + b); - - [q_row_non_first * (fingerprint_cur - fingerprint_prev * (alpha - perf_term))] - }); - - meta.create_gate("challenges consistency", |meta| { - let q_row_non_first = meta.query_selector(q_row_non_first); - let alpha_prev = meta.query_advice(alpha, Rotation::prev()); - let alpha_cur = meta.query_advice(alpha, Rotation::cur()); - let gamma_prev = meta.query_advice(gamma, Rotation::prev()); - let gamma_cur = meta.query_advice(gamma, Rotation::cur()); - [ - q_row_non_first * (alpha_prev - alpha_cur), - q_row_non_first * (gamma_prev - gamma_cur), - ] - }); - Self { - fingerprints, - permutation_instance, - q_row_non_first, - alpha, - gamma, - _phantom: PhantomData:: {}, - } - } -} - -impl PermutationCircuitConfig { +impl PermutationChipConfig { + /// assign pub fn assign( &self, region: &mut Region<'_, F>, @@ -111,7 +50,6 @@ impl PermutationCircuitConfig { Error, > { let mut offset = 0; - // Constrain raw_public_input cells to public inputs let alpha_first_cell = region.assign_advice( || format!("alpha at index {}", offset), self.alpha, @@ -144,7 +82,7 @@ impl PermutationCircuitConfig { let mut last_fingerprint_cell = None; for (_, row) in col_values.iter().enumerate() { - self.q_row_non_first.enable(region, offset); + self.q_row_non_first.enable(region, offset)?; let perf_term = { let tmp = row @@ -188,79 +126,71 @@ impl PermutationCircuitConfig { last_fingerprint_cell.unwrap(), )) } - - /// Get number of rows required. - pub fn get_num_rows_required(num_rw: usize) -> usize { - unimplemented!() - } } /// permutation fingerprint gadget #[derive(Debug, Clone)] -pub struct PermutationCircuit { - alpha: Value, - gamma: Value, - prev_continuous_fingerprint: Value, - col_values: Vec>>, +pub struct PermutationChip { + /// config + pub config: PermutationChipConfig, } -impl SubCircuit for PermutationCircuit { - type Config = PermutationCircuitConfig; - - fn unusable_rows() -> usize { - // No column queried at more than 3 distinct rotations, so returns 6 as - // minimum unusable rows. - 6 - } - - fn new_from_block(_block: &witness::Block) -> Self { - unimplemented!() - } +impl PermutationChip { + /// configure + pub fn configure( + meta: &mut ConstraintSystem, + cols: Vec>, + ) -> PermutationChipConfig { + let fingerprints = meta.advice_column(); + let alpha = meta.advice_column(); + let gamma = meta.advice_column(); + let q_row_non_first = meta.selector(); - /// Return the minimum number of rows required to prove the block - fn min_num_rows_block(block: &witness::Block) -> (usize, usize) { - unimplemented!() - } + meta.create_gate("permutation fingerprint update logic", |meta| { + let alpha = meta.query_advice(alpha, Rotation::cur()); + let gamma = meta.query_advice(gamma, Rotation::cur()); + let q_row_non_first = meta.query_selector(q_row_non_first); + let cols_cur_exprs = cols + .iter() + .map(|col| meta.query_advice(*col, Rotation::cur())) + .collect::>>(); + let fingerprint_prev = meta.query_advice(fingerprints, Rotation::prev()); + let fingerprint_cur = meta.query_advice(fingerprints, Rotation::cur()); - /// Make the assignments to the TxCircuit - fn synthesize_sub( - &self, - config: &Self::Config, - challenges: &Challenges>, - layouter: &mut impl Layouter, - ) -> Result<(), Error> { - let (alpha_cell, gamma_cell, prev_continuous_fingerprint_cell, new_fingerprint_cell) = - layouter.assign_region( - || "permutation circuit", - |mut region| { - let cells = config.assign( - &mut region, - self.alpha, - self.gamma, - self.prev_continuous_fingerprint, - &self.col_values, - )?; + let power_of_gamma = std::iter::successors(1.expr().into(), |prev: &Expression| { + (prev.clone() * gamma.clone()).into() + }) + .take(cols.len()) + .collect::>>(); - Ok(cells) - }, - )?; - layouter.constrain_instance(alpha_cell.cell(), config.permutation_instance, 0)?; - layouter.constrain_instance(gamma_cell.cell(), config.permutation_instance, 1)?; - layouter.constrain_instance( - prev_continuous_fingerprint_cell.cell(), - config.permutation_instance, - 2, - )?; - layouter.constrain_instance(new_fingerprint_cell.cell(), config.permutation_instance, 2)?; + let perf_term = cols_cur_exprs + .iter() + .zip(power_of_gamma.iter()) + .map(|(a, b)| a.clone() * b.clone()) + .fold(0.expr(), |a, b| a + b); - Ok(()) - } + [q_row_non_first * (fingerprint_cur - fingerprint_prev * (alpha - perf_term))] + }); - /// Compute the public inputs for this circuit. - fn instance(&self) -> Vec> { - // TODO - unimplemented!() + meta.create_gate("challenges consistency", |meta| { + let q_row_non_first = meta.query_selector(q_row_non_first); + let alpha_prev = meta.query_advice(alpha, Rotation::prev()); + let alpha_cur = meta.query_advice(alpha, Rotation::cur()); + let gamma_prev = meta.query_advice(gamma, Rotation::prev()); + let gamma_cur = meta.query_advice(gamma, Rotation::cur()); + [ + q_row_non_first.clone() * (alpha_prev - alpha_cur), + q_row_non_first * (gamma_prev - gamma_cur), + ] + }); + PermutationChipConfig { + fingerprints, + q_row_non_first, + alpha, + gamma, + _phantom: PhantomData:: {}, + } } } -impl PermutationCircuit {} +impl PermutationChip {} diff --git a/zkevm-circuits/src/evm_circuit.rs b/zkevm-circuits/src/evm_circuit.rs index cc1927768d..2eba1648cf 100644 --- a/zkevm-circuits/src/evm_circuit.rs +++ b/zkevm-circuits/src/evm_circuit.rs @@ -1,5 +1,6 @@ //! The EVM circuit implementation. +use gadgets::permutation::{PermutationChip, PermutationChipConfig}; use halo2_proofs::{ circuit::{Layouter, SimpleFloorPlanner, Value}, plonk::*, @@ -50,6 +51,17 @@ pub struct EvmCircuitConfig { copy_table: CopyTable, keccak_table: KeccakTable, exp_table: ExpTable, + + // rw permutation config + rw_permutation_config: PermutationChipConfig, + + // rw_table pi for permutation + pi_rw_table: Column, + // challenge pi for permutation + pi_permutation_challenges: Column, + // fingerprints pi for permutation + prev_permutation_fingerprint: Column, + next_permutation_fingerprint: Column, } /// Circuit configuration arguments @@ -126,6 +138,16 @@ impl SubCircuitConfig for EvmCircuitConfig { u8_table.annotate_columns(meta); u16_table.annotate_columns(meta); + let rw_permutation_config = PermutationChip::configure( + meta, + >::advice_columns(&rw_table), + ); + + let pi_rw_table = meta.instance_column(); + let pi_permutation_challenges = meta.instance_column(); + let prev_permutation_fingerprint = meta.instance_column(); + let next_permutation_fingerprint = meta.instance_column(); + Self { fixed_table, u8_table, @@ -138,6 +160,11 @@ impl SubCircuitConfig for EvmCircuitConfig { copy_table, keccak_table, exp_table, + rw_permutation_config, + pi_rw_table, + pi_permutation_challenges, + prev_permutation_fingerprint, + next_permutation_fingerprint, } } } @@ -267,7 +294,96 @@ impl SubCircuit for EvmCircuit { let block = self.block.as_ref().unwrap(); config.load_fixed_table(layouter, self.fixed_table_tags.clone())?; - config.execution.assign_block(layouter, block, challenges) + + config.execution.assign_block(layouter, block, challenges)?; + + // permutation cells + let ( + alpha_cell, + gamma_cell, + prev_continuous_fingerprint_cell, + next_continuous_fingerprint_cell, + ) = layouter.assign_region( + || "rw table permutation fingerprint", + |mut region| { + config.rw_permutation_config.assign( + &mut region, + Value::known(block.permu_alpha), + Value::known(block.permu_gamma), + Value::known(block.permu_prev_continuous_fingerprint), + &block + .rws + .table_assignments(true) + .iter() + .map(|row| { + row.table_assignment::() + .unwrap() + .values() + .to_vec() + .iter() + .map(|f| Value::known(*f)) + .collect::>>() + }) + .collect::>>>(), + ) + }, + )?; + // constrain permutation challenges + [alpha_cell, gamma_cell] + .iter() + .enumerate() + .try_for_each(|(i, cell)| { + layouter.constrain_instance(cell.cell(), config.pi_permutation_challenges, i) + })?; + // constraints prev,next fingerprints + [ + ( + prev_continuous_fingerprint_cell, + config.prev_permutation_fingerprint, + ), + ( + next_continuous_fingerprint_cell, + config.next_permutation_fingerprint, + ), + ] + .iter() + .try_for_each(|(cell, column)| layouter.constrain_instance(cell.cell(), *column, 0))?; + + let rw_table_first_n_last_cells = config.rw_table.load( + layouter, + &block.rws.table_assignments(true), + block.circuits_params.max_rws, + )?; + + // constrain rw table first/last row to public input + rw_table_first_n_last_cells + .iter() + .enumerate() + .try_for_each(|(i, cell)| { + layouter.constrain_instance(cell.cell(), config.pi_rw_table, i) + })?; + Ok(()) + } + + /// Compute the public inputs for this circuit. + fn instance(&self) -> Vec> { + let block = self.block.as_ref().unwrap(); + let rws_assignments = block.rws.table_assignments(true); + + assert!(rws_assignments.len() > 0); + + let rws_values = [0, rws_assignments.len() - 1] // get first/last row and concat + .iter() + .map(|i| { + rws_assignments + .get(*i) + .map(|row| row.table_assignment().unwrap().values()) + .unwrap_or_default() + }) + .flatten() + .collect::>(); + + vec![rws_values] } } @@ -413,11 +529,6 @@ impl Circuit for EvmCircuit { block.circuits_params.max_calldata, )?; block.rws.check_rw_counter_sanity(); - config.rw_table.load( - &mut layouter, - &block.rws.table_assignments(true), - block.circuits_params.max_rws, - )?; config .bytecode_table .load(&mut layouter, block.bytecodes.clone())?; diff --git a/zkevm-circuits/src/lib.rs b/zkevm-circuits/src/lib.rs index 769923cd1e..fe25729425 100644 --- a/zkevm-circuits/src/lib.rs +++ b/zkevm-circuits/src/lib.rs @@ -26,7 +26,6 @@ pub mod exp_circuit; pub mod keccak_circuit; #[allow(dead_code, reason = "under active development")] pub mod mpt_circuit; -pub mod permutation_circuit; pub mod pi_circuit; pub mod root_circuit; pub mod state_circuit; diff --git a/zkevm-circuits/src/state_circuit.rs b/zkevm-circuits/src/state_circuit.rs index 7a7b80db81..821847b368 100644 --- a/zkevm-circuits/src/state_circuit.rs +++ b/zkevm-circuits/src/state_circuit.rs @@ -27,12 +27,13 @@ use eth_types::{Address, Field, Word}; use gadgets::{ batched_is_zero::{BatchedIsZeroChip, BatchedIsZeroConfig}, binary_number::{BinaryNumberChip, BinaryNumberConfig}, + permutation::{PermutationChip, PermutationChipConfig}, }; use halo2_proofs::{ circuit::{Layouter, Region, Value}, plonk::{ - Advice, Column, ConstraintSystem, Error, Expression, FirstPhase, Fixed, SecondPhase, - VirtualCells, + Advice, Column, ConstraintSystem, Error, Expression, FirstPhase, Fixed, Instance, + SecondPhase, VirtualCells, }, poly::Rotation, }; @@ -69,6 +70,17 @@ pub struct StateCircuitConfig { lookups: LookupsConfig, // External tables mpt_table: MptTable, + + // rw permutation config + rw_permutation_config: PermutationChipConfig, + + // rw_table pi for permutation + pi_rw_table: Column, + // challenge pi for permutation + pi_permutation_challenges: Column, + // fingerprints pi for permutation + prev_permutation_fingerprint: Column, + next_permutation_fingerprint: Column, _marker: PhantomData, } @@ -149,6 +161,11 @@ impl SubCircuitConfig for StateCircuitConfig { let lexicographic_ordering = LexicographicOrderingConfig::configure(meta, sort_keys, lookups, power_of_randomness); + let rw_permutation_config = PermutationChip::configure( + meta, + >::advice_columns(&rw_table), + ); + // annotate columns rw_table.annotate_columns(meta); mpt_table.annotate_columns(meta); @@ -156,6 +173,14 @@ impl SubCircuitConfig for StateCircuitConfig { u10_table.annotate_columns(meta); u16_table.annotate_columns(meta); + // rw_table pi for permutation + let pi_rw_table = meta.instance_column(); + // challenge pi for permutation + let pi_permutation_challenges = meta.instance_column(); + // fingerprints pi for permutation + let prev_permutation_fingerprint = meta.instance_column(); + let next_permutation_fingerprint = meta.instance_column(); + let config = Self { selector, sort_keys, @@ -168,6 +193,11 @@ impl SubCircuitConfig for StateCircuitConfig { lookups, rw_table, mpt_table, + rw_permutation_config, + pi_rw_table, + pi_permutation_challenges, + prev_permutation_fingerprint, + next_permutation_fingerprint, _marker: PhantomData::default(), }; @@ -427,12 +457,24 @@ pub struct StateCircuit { pub(crate) n_rows: usize, #[cfg(test)] overrides: HashMap<(dev::AdviceColumn, isize), F>, + + /// permutation challenge + permu_alpha: F, + permu_gamma: F, + permu_prev_continuous_fingerprint: F, + _marker: PhantomData, } impl StateCircuit { /// make a new state circuit from an RwMap - pub fn new(rw_map: RwMap, n_rows: usize) -> Self { + pub fn new( + rw_map: RwMap, + n_rows: usize, + permu_alpha: F, + permu_gamma: F, + permu_prev_continuous_fingerprint: F, + ) -> Self { let rows = rw_map.table_assignments(false); // address sorted let updates = MptUpdates::mock_from(&rows); Self { @@ -441,6 +483,9 @@ impl StateCircuit { n_rows, #[cfg(test)] overrides: HashMap::new(), + permu_alpha, + permu_gamma, + permu_prev_continuous_fingerprint, _marker: PhantomData::default(), } } @@ -450,7 +495,13 @@ impl SubCircuit for StateCircuit { type Config = StateCircuitConfig; fn new_from_block(block: &witness::Block) -> Self { - Self::new(block.rws.clone(), block.circuits_params.max_rws) + Self::new( + block.rws.clone(), + block.circuits_params.max_rws, + block.permu_alpha, + block.permu_gamma, + block.permu_prev_continuous_fingerprint, + ) } fn unusable_rows() -> usize { @@ -479,12 +530,13 @@ impl SubCircuit for StateCircuit { // Assigning to same columns in different regions should be avoided. // Here we use one single region to assign `overrides` to both rw table and // other parts. - layouter.assign_region( + let rw_table_first_n_last_cells = layouter.assign_region( || "state circuit", |mut region| { - config - .rw_table - .load_with_region(&mut region, &self.rows, self.n_rows)?; + let rw_table_first_n_last_cells = + config + .rw_table + .load_with_region(&mut region, &self.rows, self.n_rows)?; config.assign_with_region(&mut region, &self.rows, &self.updates, self.n_rows)?; #[cfg(test)] @@ -510,9 +562,69 @@ impl SubCircuit for StateCircuit { } } - Ok(()) + Ok(rw_table_first_n_last_cells) }, - ) + )?; + + // permutation cells + let ( + alpha_cell, + gamma_cell, + prev_continuous_fingerprint_cell, + next_continuous_fingerprint_cell, + ) = layouter.assign_region( + || "rw permutation fingerprint", + |mut region| { + config.rw_permutation_config.assign( + &mut region, + Value::known(self.permu_alpha), + Value::known(self.permu_gamma), + Value::known(self.permu_prev_continuous_fingerprint), + &self + .rows + .iter() + .map(|row| { + row.table_assignment::() + .unwrap() + .values() + .to_vec() + .iter() + .map(|f| Value::known(*f)) + .collect::>>() + }) + .collect::>>>(), + ) + }, + )?; + // constrain permutation challenges + [alpha_cell, gamma_cell] + .iter() + .enumerate() + .try_for_each(|(i, cell)| { + layouter.constrain_instance(cell.cell(), config.pi_permutation_challenges, i) + })?; + // constraints prev,next fingerprints + [ + ( + prev_continuous_fingerprint_cell, + config.prev_permutation_fingerprint, + ), + ( + next_continuous_fingerprint_cell, + config.next_permutation_fingerprint, + ), + ] + .iter() + .try_for_each(|(cell, column)| layouter.constrain_instance(cell.cell(), *column, 0))?; + + let pi_initial_offset = 0; + rw_table_first_n_last_cells + .iter() + .enumerate() + .try_for_each(|(i, cell)| { + layouter.constrain_instance(cell.cell(), config.pi_rw_table, pi_initial_offset + i) + })?; + Ok(()) } /// powers of randomness for instance columns diff --git a/zkevm-circuits/src/state_circuit/test.rs b/zkevm-circuits/src/state_circuit/test.rs index 8456d8113e..5f625e1bc9 100644 --- a/zkevm-circuits/src/state_circuit/test.rs +++ b/zkevm-circuits/src/state_circuit/test.rs @@ -46,7 +46,7 @@ fn test_state_circuit_ok( ..Default::default() }); - let circuit = StateCircuit::::new(rw_map, N_ROWS); + let circuit = StateCircuit::::new(rw_map, N_ROWS, Fr::from(1), Fr::from(1), Fr::from(1)); let instance = circuit.instance(); let prover = MockProver::::run(19, &circuit, instance).unwrap(); @@ -65,7 +65,13 @@ fn degree() { fn verifying_key_independent_of_rw_length() { let params = ParamsKZG::::setup(17, rand_chacha::ChaCha20Rng::seed_from_u64(2)); - let no_rows = StateCircuit::::new(RwMap::default(), N_ROWS); + let no_rows = StateCircuit::::new( + RwMap::default(), + N_ROWS, + Fr::from(1), + Fr::from(1), + Fr::from(1), + ); let one_row = StateCircuit::::new( RwMap::from(&OperationContainer { memory: vec![Operation::new( @@ -76,6 +82,9 @@ fn verifying_key_independent_of_rw_length() { ..Default::default() }), N_ROWS, + Fr::from(1), + Fr::from(1), + Fr::from(1), ); let vk_no_rows = keygen_vk(¶ms, &no_rows).unwrap(); @@ -929,6 +938,9 @@ fn variadic_size_check() { updates, overrides: HashMap::default(), n_rows: N_ROWS, + permu_alpha: Fr::from(1), + permu_gamma: Fr::from(1), + permu_prev_continuous_fingerprint: Fr::from(1), _marker: std::marker::PhantomData::default(), }; let power_of_randomness = circuit.instance(); @@ -957,6 +969,9 @@ fn variadic_size_check() { updates, overrides: HashMap::default(), n_rows: N_ROWS, + permu_alpha: Fr::from(1), + permu_gamma: Fr::from(1), + permu_prev_continuous_fingerprint: Fr::from(1), _marker: std::marker::PhantomData::default(), }; let power_of_randomness = circuit.instance(); @@ -997,6 +1012,9 @@ fn prover(rows: Vec, overrides: HashMap<(AdviceColumn, isize), Fr>) -> MockP updates, overrides, n_rows: N_ROWS, + permu_alpha: Fr::from(1), + permu_gamma: Fr::from(1), + permu_prev_continuous_fingerprint: Fr::from(1), _marker: std::marker::PhantomData::default(), }; let instance = circuit.instance(); diff --git a/zkevm-circuits/src/super_circuit.rs b/zkevm-circuits/src/super_circuit.rs index 9945e8fbee..5972e3f65a 100644 --- a/zkevm-circuits/src/super_circuit.rs +++ b/zkevm-circuits/src/super_circuit.rs @@ -59,12 +59,11 @@ use crate::{ evm_circuit::{EvmCircuit, EvmCircuitConfig, EvmCircuitConfigArgs}, exp_circuit::{ExpCircuit, ExpCircuitConfig}, keccak_circuit::{KeccakCircuit, KeccakCircuitConfig, KeccakCircuitConfigArgs}, - permutation_circuit::{PermutationCircuitConfig, PermutationCircuitConfigArgs}, pi_circuit::{PiCircuit, PiCircuitConfig, PiCircuitConfigArgs}, state_circuit::{StateCircuit, StateCircuitConfig, StateCircuitConfigArgs}, table::{ - BlockTable, BytecodeTable, CopyTable, ExpTable, KeccakTable, LookupTable, MptTable, - RwTable, TxTable, UXTable, + BlockTable, BytecodeTable, CopyTable, ExpTable, KeccakTable, MptTable, RwTable, TxTable, + UXTable, }, tx_circuit::{TxCircuit, TxCircuitConfig, TxCircuitConfigArgs}, util::{log2_ceil, Challenges, SubCircuit, SubCircuitConfig}, @@ -98,7 +97,6 @@ pub struct SuperCircuitConfig { keccak_circuit: KeccakCircuitConfig, pi_circuit: PiCircuitConfig, exp_circuit: ExpCircuitConfig, - permutation_circuit: PermutationCircuitConfig, } /// Circuit configuration arguments @@ -125,7 +123,7 @@ impl SubCircuitConfig for SuperCircuitConfig { ) -> Self { let tx_table = TxTable::construct(meta); - // TODO reserve offset 0 to adapt column from previous supercircuit chunk + // TODO reserve offset 0 to adapt column from previous supercircuit chunk (via public input) let chronological_rw_table = RwTable::construct(meta); let rw_table = RwTable::construct(meta); @@ -150,14 +148,6 @@ impl SubCircuitConfig for SuperCircuitConfig { power_of_randomness[0].clone(), ); - // TODO support passing arbitrary columns set for permutation fingerprints - let permutation_circuit = PermutationCircuitConfig::new( - meta, - PermutationCircuitConfigArgs { - cols: >::advice_columns(&chronological_rw_table), - }, - ); - let keccak_circuit = KeccakCircuitConfig::new( meta, KeccakCircuitConfigArgs { @@ -246,7 +236,6 @@ impl SubCircuitConfig for SuperCircuitConfig { keccak_circuit, pi_circuit, exp_circuit, - permutation_circuit, } } } diff --git a/zkevm-circuits/src/table/rw_table.rs b/zkevm-circuits/src/table/rw_table.rs index 6e8ffc4257..a78a268f7d 100644 --- a/zkevm-circuits/src/table/rw_table.rs +++ b/zkevm-circuits/src/table/rw_table.rs @@ -1,3 +1,5 @@ +use halo2_proofs::circuit::AssignedCell; + use super::*; /// The RwTable shared between EVM Circuit and State Circuit, which contains @@ -86,7 +88,8 @@ impl RwTable { region: &mut Region<'_, F>, offset: usize, row: &RwRow>, - ) -> Result<(), Error> { + ) -> Result>, Error> { + let mut assigned_cells = vec![]; for (column, value) in [ (self.rw_counter, row.rw_counter), (self.is_write, row.is_write), @@ -95,7 +98,12 @@ impl RwTable { (self.address, row.address), (self.field_tag, row.field_tag), ] { - region.assign_advice(|| "assign rw row on rw table", column, offset, || value)?; + assigned_cells.push(region.assign_advice( + || "assign rw row on rw table", + column, + offset, + || value, + )?); } for (column, value) in [ (self.storage_key, row.storage_key), @@ -103,10 +111,15 @@ impl RwTable { (self.value_prev, row.value_prev), (self.init_val, row.init_val), ] { - value.assign_advice(region, || "assign rw row on rw table", column, offset)?; + assigned_cells.extend( + value + .assign_advice(region, || "assign rw row on rw table", column, offset)? + .limbs + .clone(), + ); } - Ok(()) + Ok(assigned_cells) } /// Assign the `RwTable` from a `RwMap`, following the same @@ -116,7 +129,7 @@ impl RwTable { layouter: &mut impl Layouter, rws: &[Rw], n_rows: usize, - ) -> Result<(), Error> { + ) -> Result>, Error> { layouter.assign_region( || "rw table", |mut region| self.load_with_region(&mut region, rws, n_rows), @@ -128,11 +141,15 @@ impl RwTable { region: &mut Region<'_, F>, rws: &[Rw], n_rows: usize, - ) -> Result<(), Error> { + ) -> Result>, Error> { + let mut assigned_cells = vec![]; let (rows, _) = RwMap::table_assignments_prepad(rws, n_rows); for (offset, row) in rows.iter().enumerate() { - self.assign(region, offset, &row.table_assignment())?; + let row_assigned_cells = self.assign(region, offset, &row.table_assignment())?; + if offset == 0 || offset == rows.len() - 1 { + assigned_cells.extend(row_assigned_cells); + } } - Ok(()) + Ok(assigned_cells) } } diff --git a/zkevm-circuits/src/test_util.rs b/zkevm-circuits/src/test_util.rs index 0cffa92f9a..a779305b9a 100644 --- a/zkevm-circuits/src/test_util.rs +++ b/zkevm-circuits/src/test_util.rs @@ -219,7 +219,13 @@ impl CircuitTestBuilder { { let rows_needed = StateCircuit::::min_num_rows_block(&block).1; let k = cmp::max(log2_ceil(rows_needed + NUM_BLINDING_ROWS), 18); - let state_circuit = StateCircuit::::new(block.rws, params.max_rws); + let state_circuit = StateCircuit::::new( + block.rws, + params.max_rws, + block.permu_alpha, + block.permu_gamma, + block.permu_prev_continuous_fingerprint, + ); let instance = state_circuit.instance(); let prover = MockProver::::run(k, &state_circuit, instance).unwrap(); // Skip verification of Start rows to accelerate testing diff --git a/zkevm-circuits/src/util.rs b/zkevm-circuits/src/util.rs index ff3eba5e39..e8da067cff 100644 --- a/zkevm-circuits/src/util.rs +++ b/zkevm-circuits/src/util.rs @@ -19,8 +19,6 @@ pub use gadgets::util::Expr; pub mod cell_manager; /// Cell Placement strategies pub mod cell_placement_strategy; -/// Permutation fingerprints gadget -pub mod permutation_fingerprints; /// Steal the expression from gate pub fn query_expression( diff --git a/zkevm-circuits/src/witness/block.rs b/zkevm-circuits/src/witness/block.rs index ff790740f2..57b7894f40 100644 --- a/zkevm-circuits/src/witness/block.rs +++ b/zkevm-circuits/src/witness/block.rs @@ -50,6 +50,13 @@ pub struct Block { pub keccak_inputs: Vec>, /// Original Block from geth pub eth_block: eth_types::Block, + + /// permutation challenge alpha + pub permu_alpha: F, + /// permutation challenge gamma + pub permu_gamma: F, + /// pre permutation fingerprint + pub permu_prev_continuous_fingerprint: F, } impl Block { @@ -244,6 +251,10 @@ pub fn block_convert( let mut block = Block { // randomness: F::from(0x100), // Special value to reveal elements after RLC randomness: F::from(0xcafeu64), + // TODO get permutation fingerprint & challenges + permu_alpha: F::from(1), + permu_gamma: F::from(1), + permu_prev_continuous_fingerprint: F::from(1), context: block.into(), rws, txs: block.txs().to_vec(),