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

Commit

Permalink
permutation chip implemetation
Browse files Browse the repository at this point in the history
  • Loading branch information
hero78119 committed Oct 4, 2023
1 parent 7a2d655 commit 043b70e
Show file tree
Hide file tree
Showing 12 changed files with 379 additions and 186 deletions.
1 change: 1 addition & 0 deletions gadgets/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
1 change: 1 addition & 0 deletions gadgets/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
214 changes: 72 additions & 142 deletions zkevm-circuits/src/permutation_circuit.rs → gadgets/src/permutation.rs
Original file line number Diff line number Diff line change
@@ -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<F: Field> {
pub struct PermutationChipConfig<F> {
// 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
q_row_non_first: Selector, // 1 between (first, end], 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> {
impl<F: Field> PermutationChipConfig<F> {
/// assign
pub fn assign(
&self,
region: &mut Region<'_, F>,
Expand All @@ -111,7 +50,6 @@ impl<F: Field> PermutationCircuitConfig<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,
Expand Down Expand Up @@ -144,7 +82,7 @@ impl<F: Field> PermutationCircuitConfig<F> {

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
Expand Down Expand Up @@ -188,79 +126,71 @@ impl<F: Field> PermutationCircuitConfig<F> {
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>>>,
pub struct PermutationChip<F: Field> {
/// config
pub config: PermutationChipConfig<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!()
}
impl<F: Field> PermutationChip<F> {
/// configure
pub fn configure(
meta: &mut ConstraintSystem<F>,
cols: Vec<Column<Advice>>,
) -> PermutationChipConfig<F> {
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<F>) -> (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::<Vec<Expression<F>>>();
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<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,
)?;
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>>>();

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

impl<F: Field> PermutationCircuit<F> {}
impl<F: Field> PermutationChip<F> {}
Loading

0 comments on commit 043b70e

Please sign in to comment.