Use Column<Any> in Permutation::Argument

This commit is contained in:
therealyingtong 2021-02-17 21:13:25 +08:00
parent 0a3933b76a
commit a19dc68dee
12 changed files with 130 additions and 55 deletions

View file

@ -182,7 +182,7 @@ fn bench_with_k(name: &str, k: u32, c: &mut Criterion) {
let b = meta.advice_column(); let b = meta.advice_column();
let c = meta.advice_column(); let c = meta.advice_column();
let perm = meta.permutation(&[a, b, c]); let perm = meta.permutation(&[a.into(), b.into(), c.into()]);
let sm = meta.fixed_column(); let sm = meta.fixed_column();
let sa = meta.fixed_column(); let sa = meta.fixed_column();

View file

@ -257,8 +257,8 @@ fn main() {
let d = meta.advice_column(); let d = meta.advice_column();
let p = meta.instance_column(); let p = meta.instance_column();
let perm = meta.permutation(&[a, b, c]); let perm = meta.permutation(&[a.into(), b.into(), c.into()]);
let perm2 = meta.permutation(&[a, b, c]); let perm2 = meta.permutation(&[a.into(), b.into(), c.into()]);
let sm = meta.fixed_column(); let sm = meta.fixed_column();
let sa = meta.fixed_column(); let sa = meta.fixed_column();

View file

@ -196,7 +196,7 @@ impl<F: FieldExt> Circuit<F> for MyCircuit<F> {
let c = meta.advice_column(); let c = meta.advice_column();
let p = meta.instance_column(); let p = meta.instance_column();
let perm = meta.permutation(&[a, b, c]); let perm = meta.permutation(&[a.into(), b.into(), c.into()]);
let sm = meta.fixed_column(); let sm = meta.fixed_column();
let sa = meta.fixed_column(); let sa = meta.fixed_column();

View file

@ -73,7 +73,13 @@ impl<F: FieldExt> FieldChip<F> {
advice: [Column<Advice>; 2], advice: [Column<Advice>; 2],
instance: Column<Instance>, instance: Column<Instance>,
) -> FieldConfig { ) -> FieldConfig {
let perm = Permutation::new(meta, &advice); let perm = Permutation::new(
meta,
&advice
.iter()
.map(|column| (*column).into())
.collect::<Vec<_>>(),
);
let s_mul = meta.fixed_column(); let s_mul = meta.fixed_column();
let s_pub = meta.fixed_column(); let s_pub = meta.fixed_column();

View file

@ -46,11 +46,11 @@ pub struct Permutation {
impl Permutation { impl Permutation {
/// Configures a new permutation for the given columns. /// Configures a new permutation for the given columns.
pub fn new<F: FieldExt>(meta: &mut ConstraintSystem<F>, columns: &[Column<Advice>]) -> Self { pub fn new<F: FieldExt>(meta: &mut ConstraintSystem<F>, columns: &[Column<Any>]) -> Self {
let index = meta.permutation(columns); let index = meta.permutation(columns);
Permutation { Permutation {
index, index,
mapping: columns.iter().map(|c| (*c).into()).collect(), mapping: columns.iter().copied().collect(),
} }
} }
} }

View file

@ -396,8 +396,8 @@ fn test_proving() {
let d = meta.advice_column(); let d = meta.advice_column();
let p = meta.instance_column(); let p = meta.instance_column();
let perm = meta.permutation(&[a, b, c]); let perm = meta.permutation(&[a.into(), b.into(), c.into()]);
let perm2 = meta.permutation(&[a, b, c]); let perm2 = meta.permutation(&[a.into(), b.into(), c.into()]);
let sm = meta.fixed_column(); let sm = meta.fixed_column();
let sa = meta.fixed_column(); let sa = meta.fixed_column();

View file

@ -397,12 +397,12 @@ impl<F: Field> Default for ConstraintSystem<F> {
} }
impl<F: Field> ConstraintSystem<F> { impl<F: Field> ConstraintSystem<F> {
/// Add a permutation argument for some advice columns /// Add a permutation argument for some columns
pub fn permutation(&mut self, columns: &[Column<Advice>]) -> usize { pub fn permutation(&mut self, columns: &[Column<Any>]) -> usize {
let index = self.permutations.len(); let index = self.permutations.len();
for column in columns { for column in columns {
self.query_advice_index(*column, Rotation::cur()); self.query_any_index(*column, Rotation::cur());
} }
self.permutations self.permutations
.push(permutation::Argument::new(columns.to_vec())); .push(permutation::Argument::new(columns.to_vec()));

View file

@ -1,6 +1,6 @@
//! Implementation of a PLONK permutation argument. //! Implementation of a PLONK permutation argument.
use super::circuit::{Advice, Column}; use super::circuit::{Any, Column};
use crate::{ use crate::{
arithmetic::CurveAffine, arithmetic::CurveAffine,
poly::{Coeff, ExtendedLagrangeCoeff, LagrangeCoeff, Polynomial}, poly::{Coeff, ExtendedLagrangeCoeff, LagrangeCoeff, Polynomial},
@ -16,11 +16,11 @@ use std::io;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub(crate) struct Argument { pub(crate) struct Argument {
/// A sequence of columns involved in the argument. /// A sequence of columns involved in the argument.
columns: Vec<Column<Advice>>, columns: Vec<Column<Any>>,
} }
impl Argument { impl Argument {
pub(crate) fn new(columns: Vec<Column<Advice>>) -> Self { pub(crate) fn new(columns: Vec<Column<Any>>) -> Self {
Argument { columns } Argument { columns }
} }
@ -40,7 +40,7 @@ impl Argument {
std::cmp::max(self.columns.len() + 1, 2) std::cmp::max(self.columns.len() + 1, 2)
} }
pub(crate) fn get_columns(&self) -> Vec<Column<Advice>> { pub(crate) fn get_columns(&self) -> Vec<Column<Any>> {
self.columns.clone() self.columns.clone()
} }
} }

View file

@ -1,6 +1,7 @@
use ff::Field; use ff::Field;
use std::iter; use std::iter;
use super::super::circuit::Any;
use super::{Argument, ProvingKey}; use super::{Argument, ProvingKey};
use crate::{ use crate::{
arithmetic::{eval_polynomial, parallelize, BatchInvert, Curve, CurveAffine, FieldExt}, arithmetic::{eval_polynomial, parallelize, BatchInvert, Curve, CurveAffine, FieldExt},
@ -36,6 +37,8 @@ impl Argument {
pk: &plonk::ProvingKey<C>, pk: &plonk::ProvingKey<C>,
pkey: &ProvingKey<C>, pkey: &ProvingKey<C>,
advice: &[Polynomial<C::Scalar, LagrangeCoeff>], advice: &[Polynomial<C::Scalar, LagrangeCoeff>],
fixed: &[Polynomial<C::Scalar, LagrangeCoeff>],
instance: &[Polynomial<C::Scalar, LagrangeCoeff>],
beta: ChallengeBeta<C>, beta: ChallengeBeta<C>,
gamma: ChallengeGamma<C>, gamma: ChallengeGamma<C>,
transcript: &mut T, transcript: &mut T,
@ -47,53 +50,63 @@ impl Argument {
// (p_j(\omega^i) + \delta^j \omega^i \beta + \gamma) / // (p_j(\omega^i) + \delta^j \omega^i \beta + \gamma) /
// (p_j(\omega^i) + \beta s_j(\omega^i) + \gamma) // (p_j(\omega^i) + \beta s_j(\omega^i) + \gamma)
// //
// where p_j(X) is the jth advice column in this permutation, // where p_j(X) is the jth column in this permutation,
// and i is the ith row of the column. // and i is the ith row of the column.
let mut modified_advice = vec![C::Scalar::one(); params.n as usize]; let mut modified_values = vec![C::Scalar::one(); params.n as usize];
// Iterate over each column of the permutation // Iterate over each column of the permutation
for (&column, permuted_column_values) in self.columns.iter().zip(pkey.permutations.iter()) { for (&column, permuted_column_values) in self.columns.iter().zip(pkey.permutations.iter()) {
parallelize(&mut modified_advice, |modified_advice, start| { let values = match column.column_type() {
for ((modified_advice, advice_value), permuted_advice_value) in modified_advice Any::Advice => advice,
Any::Fixed => fixed,
Any::Instance => instance,
};
parallelize(&mut modified_values, |modified_values, start| {
for ((modified_values, value), permuted_value) in modified_values
.iter_mut() .iter_mut()
.zip(advice[column.index()][start..].iter()) .zip(values[column.index()][start..].iter())
.zip(permuted_column_values[start..].iter()) .zip(permuted_column_values[start..].iter())
{ {
*modified_advice *= &(*beta * permuted_advice_value + &*gamma + advice_value); *modified_values *= &(*beta * permuted_value + &*gamma + value);
} }
}); });
} }
// Invert to obtain the denominator for the permutation product polynomial // Invert to obtain the denominator for the permutation product polynomial
modified_advice.batch_invert(); modified_values.batch_invert();
// Iterate over each column again, this time finishing the computation // Iterate over each column again, this time finishing the computation
// of the entire fraction by computing the numerators // of the entire fraction by computing the numerators
let mut deltaomega = C::Scalar::one(); let mut deltaomega = C::Scalar::one();
for &column in self.columns.iter() { for &column in self.columns.iter() {
let omega = domain.get_omega(); let omega = domain.get_omega();
parallelize(&mut modified_advice, |modified_advice, start| { let values = match column.column_type() {
Any::Advice => advice,
Any::Fixed => fixed,
Any::Instance => instance,
};
parallelize(&mut modified_values, |modified_values, start| {
let mut deltaomega = deltaomega * &omega.pow_vartime(&[start as u64, 0, 0, 0]); let mut deltaomega = deltaomega * &omega.pow_vartime(&[start as u64, 0, 0, 0]);
for (modified_advice, advice_value) in modified_advice for (modified_values, value) in modified_values
.iter_mut() .iter_mut()
.zip(advice[column.index()][start..].iter()) .zip(values[column.index()][start..].iter())
{ {
// Multiply by p_j(\omega^i) + \delta^j \omega^i \beta // Multiply by p_j(\omega^i) + \delta^j \omega^i \beta
*modified_advice *= &(deltaomega * &*beta + &*gamma + advice_value); *modified_values *= &(deltaomega * &*beta + &*gamma + value);
deltaomega *= &omega; deltaomega *= &omega;
} }
}); });
deltaomega *= &C::Scalar::DELTA; deltaomega *= &C::Scalar::DELTA;
} }
// The modified_advice vector is a vector of products of fractions // The modified_values vector is a vector of products of fractions
// of the form // of the form
// //
// (p_j(\omega^i) + \delta^j \omega^i \beta + \gamma) / // (p_j(\omega^i) + \delta^j \omega^i \beta + \gamma) /
// (p_j(\omega^i) + \beta s_j(\omega^i) + \gamma) // (p_j(\omega^i) + \beta s_j(\omega^i) + \gamma)
// //
// where i is the index into modified_advice, for the jth column in // where i is the index into modified_values, for the jth column in
// the permutation // the permutation
// Compute the evaluations of the permutation product polynomial // Compute the evaluations of the permutation product polynomial
@ -102,7 +115,7 @@ impl Argument {
for row in 1..(params.n as usize) { for row in 1..(params.n as usize) {
let mut tmp = z[row - 1]; let mut tmp = z[row - 1];
tmp *= &modified_advice[row]; tmp *= &modified_values[row];
z.push(tmp); z.push(tmp);
} }
let z = domain.lagrange_from_vec(z); let z = domain.lagrange_from_vec(z);
@ -139,6 +152,8 @@ impl<C: CurveAffine> Committed<C> {
p: &'a Argument, p: &'a Argument,
pkey: &'a ProvingKey<C>, pkey: &'a ProvingKey<C>,
advice_cosets: &'a [Polynomial<C::Scalar, ExtendedLagrangeCoeff>], advice_cosets: &'a [Polynomial<C::Scalar, ExtendedLagrangeCoeff>],
fixed_cosets: &'a [Polynomial<C::Scalar, ExtendedLagrangeCoeff>],
instance_cosets: &'a [Polynomial<C::Scalar, ExtendedLagrangeCoeff>],
beta: ChallengeBeta<C>, beta: ChallengeBeta<C>,
gamma: ChallengeGamma<C>, gamma: ChallengeGamma<C>,
) -> ( ) -> (
@ -146,7 +161,6 @@ impl<C: CurveAffine> Committed<C> {
impl Iterator<Item = Polynomial<C::Scalar, ExtendedLagrangeCoeff>> + 'a, impl Iterator<Item = Polynomial<C::Scalar, ExtendedLagrangeCoeff>> + 'a,
) { ) {
let domain = &pk.vk.domain; let domain = &pk.vk.domain;
let expressions = iter::empty() let expressions = iter::empty()
// l_0(X) * (1 - z(X)) = 0 // l_0(X) * (1 - z(X)) = 0
.chain(Some( .chain(Some(
@ -155,21 +169,29 @@ impl<C: CurveAffine> Committed<C> {
// z(X) \prod (p(X) + \beta s_i(X) + \gamma) - z(omega^{-1} X) \prod (p(X) + \delta^i \beta X + \gamma) // z(X) \prod (p(X) + \beta s_i(X) + \gamma) - z(omega^{-1} X) \prod (p(X) + \delta^i \beta X + \gamma)
.chain(Some({ .chain(Some({
let mut left = self.permutation_product_coset.clone(); let mut left = self.permutation_product_coset.clone();
for (advice, permutation) in p for (values, permutation) in p
.columns .columns
.iter() .iter()
.map(|&column| { .map(|&column| match column.column_type() {
&advice_cosets[pk.vk.cs.get_advice_query_index(column, Rotation::cur())] Any::Advice => {
&advice_cosets[pk.vk.cs.get_any_query_index(column, Rotation::cur())]
}
Any::Fixed => {
&fixed_cosets[pk.vk.cs.get_any_query_index(column, Rotation::cur())]
}
Any::Instance => {
&instance_cosets[pk.vk.cs.get_any_query_index(column, Rotation::cur())]
}
}) })
.zip(pkey.cosets.iter()) .zip(pkey.cosets.iter())
{ {
parallelize(&mut left, |left, start| { parallelize(&mut left, |left, start| {
for ((left, advice), permutation) in left for ((left, value), permutation) in left
.iter_mut() .iter_mut()
.zip(advice[start..].iter()) .zip(values[start..].iter())
.zip(permutation[start..].iter()) .zip(permutation[start..].iter())
{ {
*left *= &(*advice + &(*beta * permutation) + &*gamma); *left *= &(*value + &(*beta * permutation) + &*gamma);
} }
}); });
} }
@ -177,14 +199,22 @@ impl<C: CurveAffine> Committed<C> {
let mut right = self.permutation_product_coset_inv.clone(); let mut right = self.permutation_product_coset_inv.clone();
let mut current_delta = *beta * &C::Scalar::ZETA; let mut current_delta = *beta * &C::Scalar::ZETA;
let step = domain.get_extended_omega(); let step = domain.get_extended_omega();
for advice in p.columns.iter().map(|&column| { for values in p.columns.iter().map(|&column| match column.column_type() {
&advice_cosets[pk.vk.cs.get_advice_query_index(column, Rotation::cur())] Any::Advice => {
&advice_cosets[pk.vk.cs.get_any_query_index(column, Rotation::cur())]
}
Any::Fixed => {
&fixed_cosets[pk.vk.cs.get_any_query_index(column, Rotation::cur())]
}
Any::Instance => {
&instance_cosets[pk.vk.cs.get_any_query_index(column, Rotation::cur())]
}
}) { }) {
parallelize(&mut right, move |right, start| { parallelize(&mut right, move |right, start| {
let mut beta_term = let mut beta_term =
current_delta * &step.pow_vartime(&[start as u64, 0, 0, 0]); current_delta * &step.pow_vartime(&[start as u64, 0, 0, 0]);
for (right, advice) in right.iter_mut().zip(advice[start..].iter()) { for (right, value) in right.iter_mut().zip(values[start..].iter()) {
*right *= &(*advice + &beta_term + &*gamma); *right *= &(*value + &beta_term + &*gamma);
beta_term *= &step; beta_term *= &step;
} }
}); });
@ -240,7 +270,7 @@ impl<C: CurveAffine> Constructed<C> {
let permutation_evals = pkey.evaluate(x); let permutation_evals = pkey.evaluate(x);
// Hash each advice evaluation // Hash permutation product evals
for eval in iter::empty() for eval in iter::empty()
.chain(Some(&permutation_product_eval)) .chain(Some(&permutation_product_eval))
.chain(Some(&permutation_product_inv_eval)) .chain(Some(&permutation_product_inv_eval))

View file

@ -1,6 +1,7 @@
use ff::Field; use ff::Field;
use std::iter; use std::iter;
use super::super::circuit::Any;
use super::{Argument, VerifyingKey}; use super::{Argument, VerifyingKey};
use crate::{ use crate::{
arithmetic::{CurveAffine, FieldExt}, arithmetic::{CurveAffine, FieldExt},
@ -71,6 +72,8 @@ impl<C: CurveAffine> Evaluated<C> {
vk: &'a plonk::VerifyingKey<C>, vk: &'a plonk::VerifyingKey<C>,
p: &'a Argument, p: &'a Argument,
advice_evals: &'a [C::Scalar], advice_evals: &'a [C::Scalar],
fixed_evals: &[C::Scalar],
instance_evals: &'a [C::Scalar],
l_0: C::Scalar, l_0: C::Scalar,
beta: ChallengeBeta<C>, beta: ChallengeBeta<C>,
gamma: ChallengeGamma<C>, gamma: ChallengeGamma<C>,
@ -85,23 +88,35 @@ impl<C: CurveAffine> Evaluated<C> {
// - z(omega^{-1} X) \prod (p(X) + \delta^i \beta X + \gamma) // - z(omega^{-1} X) \prod (p(X) + \delta^i \beta X + \gamma)
.chain(Some({ .chain(Some({
let mut left = self.permutation_product_eval; let mut left = self.permutation_product_eval;
for (advice_eval, permutation_eval) in p for (eval, permutation_eval) in p
.columns .columns
.iter() .iter()
.map(|&column| { .map(|&column| match column.column_type() {
advice_evals[vk.cs.get_advice_query_index(column, Rotation::cur())] Any::Advice => {
advice_evals[vk.cs.get_any_query_index(column, Rotation::cur())]
}
Any::Fixed => {
fixed_evals[vk.cs.get_any_query_index(column, Rotation::cur())]
}
Any::Instance => {
instance_evals[vk.cs.get_any_query_index(column, Rotation::cur())]
}
}) })
.zip(self.permutation_evals.iter()) .zip(self.permutation_evals.iter())
{ {
left *= &(advice_eval + &(*beta * permutation_eval) + &*gamma); left *= &(eval + &(*beta * permutation_eval) + &*gamma);
} }
let mut right = self.permutation_product_inv_eval; let mut right = self.permutation_product_inv_eval;
let mut current_delta = *beta * &*x; let mut current_delta = *beta * &*x;
for advice_eval in p.columns.iter().map(|&column| { for eval in p.columns.iter().map(|&column| match column.column_type() {
advice_evals[vk.cs.get_advice_query_index(column, Rotation::cur())] Any::Advice => advice_evals[vk.cs.get_any_query_index(column, Rotation::cur())],
Any::Fixed => fixed_evals[vk.cs.get_any_query_index(column, Rotation::cur())],
Any::Instance => {
instance_evals[vk.cs.get_any_query_index(column, Rotation::cur())]
}
}) { }) {
right *= &(advice_eval + &current_delta + &*gamma); right *= &(eval + &current_delta + &*gamma);
current_delta *= &C::Scalar::DELTA; current_delta *= &C::Scalar::DELTA;
} }

View file

@ -275,9 +275,10 @@ pub fn create_proof<C: CurveAffine, T: TranscriptWrite<C>, ConcreteCircuit: Circ
// Sample gamma challenge // Sample gamma challenge
let gamma = ChallengeGamma::get(transcript); let gamma = ChallengeGamma::get(transcript);
let permutations: Vec<Vec<permutation::prover::Committed<C>>> = advice let permutations: Vec<Vec<permutation::prover::Committed<C>>> = instance
.iter() .iter()
.map(|advice| -> Result<Vec<_>, Error> { .zip(advice.iter())
.map(|(instance, advice)| -> Result<Vec<_>, Error> {
// Commit to permutations, if any. // Commit to permutations, if any.
pk.vk pk.vk
.cs .cs
@ -290,6 +291,8 @@ pub fn create_proof<C: CurveAffine, T: TranscriptWrite<C>, ConcreteCircuit: Circ
pk, pk,
pkey, pkey,
&advice.advice_values, &advice.advice_values,
&pk.fixed_values,
&instance.instance_values,
beta, beta,
gamma, gamma,
transcript, transcript,
@ -316,14 +319,24 @@ pub fn create_proof<C: CurveAffine, T: TranscriptWrite<C>, ConcreteCircuit: Circ
let (permutations, permutation_expressions): (Vec<Vec<_>>, Vec<Vec<_>>) = permutations let (permutations, permutation_expressions): (Vec<Vec<_>>, Vec<Vec<_>>) = permutations
.into_iter() .into_iter()
.zip(advice.iter()) .zip(advice.iter())
.map(|(permutations, advice)| { .zip(instance.iter())
.map(|((permutations, advice), instance)| {
// Evaluate the h(X) polynomial's constraint system expressions for the permutation constraints, if any. // Evaluate the h(X) polynomial's constraint system expressions for the permutation constraints, if any.
let tmp: Vec<_> = permutations let tmp: Vec<_> = permutations
.into_iter() .into_iter()
.zip(pk.vk.cs.permutations.iter()) .zip(pk.vk.cs.permutations.iter())
.zip(pk.permutations.iter()) .zip(pk.permutations.iter())
.map(|((p, argument), pkey)| { .map(|((p, argument), pkey)| {
p.construct(pk, argument, pkey, &advice.advice_cosets, beta, gamma) p.construct(
pk,
argument,
pkey,
&advice.advice_cosets,
&pk.fixed_cosets,
&instance.instance_cosets,
beta,
gamma,
)
}) })
.collect(); .collect();

View file

@ -158,6 +158,7 @@ pub fn verify_proof<'a, C: CurveAffine, T: TranscriptRead<C>>(
|(((advice_evals, instance_evals), permutations), lookups)| { |(((advice_evals, instance_evals), permutations), lookups)| {
let fixed_evals = fixed_evals.clone(); let fixed_evals = fixed_evals.clone();
let fixed_evals_copy = fixed_evals.clone(); let fixed_evals_copy = fixed_evals.clone();
let fixed_evals_copy_copy = fixed_evals.clone();
std::iter::empty() std::iter::empty()
// Evaluate the circuit using the custom gates provided // Evaluate the circuit using the custom gates provided
@ -176,7 +177,17 @@ pub fn verify_proof<'a, C: CurveAffine, T: TranscriptRead<C>>(
.iter() .iter()
.zip(vk.cs.permutations.iter()) .zip(vk.cs.permutations.iter())
.flat_map(move |(p, argument)| { .flat_map(move |(p, argument)| {
p.expressions(vk, argument, &advice_evals, l_0, beta, gamma, x) p.expressions(
vk,
argument,
&advice_evals,
&fixed_evals_copy,
&instance_evals,
l_0,
beta,
gamma,
x,
)
}) })
.into_iter(), .into_iter(),
) )
@ -193,7 +204,7 @@ pub fn verify_proof<'a, C: CurveAffine, T: TranscriptRead<C>>(
beta, beta,
gamma, gamma,
&advice_evals, &advice_evals,
&fixed_evals_copy, &fixed_evals_copy_copy,
&instance_evals, &instance_evals,
) )
}) })