Skip to content
This repository has been archived by the owner on Jul 5, 2024. It is now read-only.

Commit

Permalink
permutation circuit to support permutation fingerprint on rw_table
Browse files Browse the repository at this point in the history
  • Loading branch information
hero78119 committed Oct 3, 2023
1 parent 4f1f56e commit 7a2d655
Show file tree
Hide file tree
Showing 8 changed files with 306 additions and 20 deletions.
2 changes: 1 addition & 1 deletion zkevm-circuits/src/copy_circuit/dev.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ impl<F: Field> Circuit<F> for CopyCircuit<F> {

config.0.rw_table.load(
&mut layouter,
&self.external_data.rws.table_assignments(),
&self.external_data.rws.table_assignments(true),
self.external_data.max_rws,
)?;

Expand Down
2 changes: 1 addition & 1 deletion zkevm-circuits/src/evm_circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,7 @@ impl<F: Field> Circuit<F> for EvmCircuit<F> {
block.rws.check_rw_counter_sanity();
config.rw_table.load(
&mut layouter,
&block.rws.table_assignments(),
&block.rws.table_assignments(true),
block.circuits_params.max_rws,
)?;
config
Expand Down
1 change: 1 addition & 0 deletions zkevm-circuits/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ 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;
Expand Down
266 changes: 266 additions & 0 deletions zkevm-circuits/src/permutation_circuit.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,266 @@
use std::marker::PhantomData;

use eth_types::Field;
use gadgets::util::Expr;
use halo2_proofs::{
circuit::{AssignedCell, Layouter, Region, Value},
plonk::{Advice, Column, ConstraintSystem, Error, Expression, Instance, Selector},
poly::Rotation,
};
use itertools::Itertools;

use crate::{
util::{Challenges, SubCircuit, SubCircuitConfig},
witness,
};

/// Config for PermutationCircuit
#[derive(Clone, Debug)]
pub struct PermutationCircuitConfig<F: Field> {
// column
fingerprints: Column<Advice>,
alpha: Column<Advice>,
gamma: Column<Advice>,
permutation_instance: Column<Instance>,

// selector
q_row_non_first: Selector, // 1 between (first, last], exclude first

_phantom: PhantomData<F>,
}

/// Circuit configuration arguments
pub struct PermutationCircuitConfigArgs {
pub cols: Vec<Column<Advice>>,
}

impl<F: Field> SubCircuitConfig<F> for PermutationCircuitConfig<F> {
type ConfigArgs = PermutationCircuitConfigArgs;

/// Return a new TxCircuitConfig
fn new(meta: &mut ConstraintSystem<F>, 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::<Vec<Expression<F>>>();
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<F>| {
(prev.clone() * gamma.clone()).into()
})
.take(cols.len())
.collect::<Vec<Expression<F>>>();

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::<F> {},
}
}
}

impl<F: Field> PermutationCircuitConfig<F> {
pub fn assign(
&self,
region: &mut Region<'_, F>,
alpha: Value<F>,
gamma: Value<F>,
prev_continuous_fingerprint: Value<F>,
col_values: &Vec<Vec<Value<F>>>,
) -> Result<
(
AssignedCell<F, F>,
AssignedCell<F, F>,
AssignedCell<F, F>,
AssignedCell<F, F>,
),
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,
offset,
|| alpha,
)?;
let gamma_first_cell = region.assign_advice(
|| format!("gamma at index {}", offset),
self.gamma,
offset,
|| gamma,
)?;
let prev_continuous_fingerprint_cell = region.assign_advice(
|| format!("fingerprint at index {}", offset),
self.fingerprints,
offset,
|| prev_continuous_fingerprint,
)?;

let power_of_gamma = {
let num_of_col = col_values.get(0).map(|x| x.len()).unwrap_or_default();
std::iter::successors(Some(Value::known(F::ONE)), |prev| {
(prev.clone() * gamma.clone()).into()
})
.take(num_of_col)
.collect::<Vec<Value<F>>>()
};

offset += 1;

let mut last_fingerprint_cell = None;
for (_, row) in col_values.iter().enumerate() {
self.q_row_non_first.enable(region, offset);

let perf_term = {
let tmp = row
.iter()
.zip_eq(power_of_gamma.iter())
.map(|(a, b)| a.zip(*b).map(|(a, b)| a * b))
.fold(Value::known(F::ZERO), |prev, cur| {
prev.zip(cur).map(|(a, b)| a + b)
});
alpha.zip(tmp).map(|(alpha, perf_term)| alpha - perf_term)
};
let fingerprint_cell = region.assign_advice(
|| format!("fingerprint at index {}", offset),
self.fingerprints,
offset,
|| perf_term,
)?;
if offset == col_values.len() {
last_fingerprint_cell = Some(fingerprint_cell);
}
region.assign_advice(
|| format!("alpha at index {}", offset),
self.alpha,
offset,
|| alpha,
)?;
region.assign_advice(
|| format!("gamma at index {}", offset),
self.gamma,
offset,
|| gamma,
)?;

offset += 1;
}

Ok((
alpha_first_cell,
gamma_first_cell,
prev_continuous_fingerprint_cell,
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<F> {
alpha: Value<F>,
gamma: Value<F>,
prev_continuous_fingerprint: Value<F>,
col_values: Vec<Vec<Value<F>>>,
}

impl<F: Field> SubCircuit<F> for PermutationCircuit<F> {
type Config = PermutationCircuitConfig<F>;

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<F>) -> Self {
unimplemented!()
}

/// Return the minimum number of rows required to prove the block
fn min_num_rows_block(block: &witness::Block<F>) -> (usize, usize) {
unimplemented!()
}

/// Make the assignments to the TxCircuit
fn synthesize_sub(
&self,
config: &Self::Config,
challenges: &Challenges<Value<F>>,
layouter: &mut impl Layouter<F>,
) -> 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,
)?;

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)?;

Ok(())
}

/// Compute the public inputs for this circuit.
fn instance(&self) -> Vec<Vec<F>> {
// TODO
unimplemented!()
}
}

impl<F: Field> PermutationCircuit<F> {}
2 changes: 1 addition & 1 deletion zkevm-circuits/src/state_circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -433,7 +433,7 @@ pub struct StateCircuit<F> {
impl<F: Field> StateCircuit<F> {
/// make a new state circuit from an RwMap
pub fn new(rw_map: RwMap, n_rows: usize) -> Self {
let rows = rw_map.table_assignments();
let rows = rw_map.table_assignments(false); // address sorted
let updates = MptUpdates::mock_from(&rows);
Self {
rows,
Expand Down
23 changes: 19 additions & 4 deletions zkevm-circuits/src/super_circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,12 @@ 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, MptTable, RwTable, TxTable,
UXTable,
BlockTable, BytecodeTable, CopyTable, ExpTable, KeccakTable, LookupTable, MptTable,
RwTable, TxTable, UXTable,
},
tx_circuit::{TxCircuit, TxCircuitConfig, TxCircuitConfigArgs},
util::{log2_ceil, Challenges, SubCircuit, SubCircuitConfig},
Expand Down Expand Up @@ -97,6 +98,7 @@ pub struct SuperCircuitConfig<F: Field> {
keccak_circuit: KeccakCircuitConfig<F>,
pi_circuit: PiCircuitConfig<F>,
exp_circuit: ExpCircuitConfig<F>,
permutation_circuit: PermutationCircuitConfig<F>,
}

/// Circuit configuration arguments
Expand All @@ -122,7 +124,11 @@ impl<F: Field> SubCircuitConfig<F> for SuperCircuitConfig<F> {
}: Self::ConfigArgs,
) -> Self {
let tx_table = TxTable::construct(meta);

// TODO reserve offset 0 to adapt column from previous supercircuit chunk
let chronological_rw_table = RwTable::construct(meta);
let rw_table = RwTable::construct(meta);

let mpt_table = MptTable::construct(meta);
let bytecode_table = BytecodeTable::construct(meta);
let block_table = BlockTable::construct(meta);
Expand All @@ -144,6 +150,14 @@ impl<F: Field> SubCircuitConfig<F> for SuperCircuitConfig<F> {
power_of_randomness[0].clone(),
);

// TODO support passing arbitrary columns set for permutation fingerprints
let permutation_circuit = PermutationCircuitConfig::new(
meta,
PermutationCircuitConfigArgs {
cols: <RwTable as LookupTable<F>>::advice_columns(&chronological_rw_table),
},
);

let keccak_circuit = KeccakCircuitConfig::new(
meta,
KeccakCircuitConfigArgs {
Expand Down Expand Up @@ -183,7 +197,7 @@ impl<F: Field> SubCircuitConfig<F> for SuperCircuitConfig<F> {
meta,
CopyCircuitConfigArgs {
tx_table: tx_table.clone(),
rw_table,
rw_table: chronological_rw_table.clone(),
bytecode_table: bytecode_table.clone(),
copy_table,
q_enable: q_copy_table,
Expand All @@ -207,7 +221,7 @@ impl<F: Field> SubCircuitConfig<F> for SuperCircuitConfig<F> {
EvmCircuitConfigArgs {
challenges,
tx_table,
rw_table,
rw_table: chronological_rw_table,
bytecode_table,
block_table: block_table.clone(),
copy_table,
Expand All @@ -232,6 +246,7 @@ impl<F: Field> SubCircuitConfig<F> for SuperCircuitConfig<F> {
keccak_circuit,
pi_circuit,
exp_circuit,
permutation_circuit,
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions zkevm-circuits/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ pub use gadgets::util::Expr;
pub mod cell_manager;
/// Cell Placement strategies
pub mod cell_placement_strategy;
/// Permutation fingerprints gadget
pub mod permutation_fingerprints;

Check failure on line 23 in zkevm-circuits/src/util.rs

View workflow job for this annotation

GitHub Actions / Linux Build

file not found for module `permutation_fingerprints`

Check failure on line 23 in zkevm-circuits/src/util.rs

View workflow job for this annotation

GitHub Actions / Light unit tests

file not found for module `permutation_fingerprints`

Check failure on line 23 in zkevm-circuits/src/util.rs

View workflow job for this annotation

GitHub Actions / Heavy unit tests

file not found for module `permutation_fingerprints`

/// Steal the expression from gate
pub fn query_expression<F: Field, T>(
Expand Down
Loading

0 comments on commit 7a2d655

Please sign in to comment.