Move permutation keygen into plonk::permutation::keygen
This commit is contained in:
parent
f63f3ff2af
commit
66240800a3
|
@ -8,7 +8,7 @@
|
|||
use crate::arithmetic::CurveAffine;
|
||||
use crate::poly::{
|
||||
commitment::ChallengeScalar, multiopen, Coeff, EvaluationDomain, ExtendedLagrangeCoeff,
|
||||
LagrangeCoeff, Polynomial,
|
||||
Polynomial,
|
||||
};
|
||||
|
||||
mod circuit;
|
||||
|
@ -28,7 +28,7 @@ pub use verifier::*;
|
|||
pub struct VerifyingKey<C: CurveAffine> {
|
||||
domain: EvaluationDomain<C::Scalar>,
|
||||
fixed_commitments: Vec<C>,
|
||||
permutation_commitments: Vec<Vec<C>>,
|
||||
permutations: Vec<permutation::VerifyingKey<C>>,
|
||||
cs: ConstraintSystem<C::Scalar>,
|
||||
}
|
||||
|
||||
|
@ -41,9 +41,7 @@ pub struct ProvingKey<C: CurveAffine> {
|
|||
l0: Polynomial<C::Scalar, ExtendedLagrangeCoeff>,
|
||||
fixed_polys: Vec<Polynomial<C::Scalar, Coeff>>,
|
||||
fixed_cosets: Vec<Polynomial<C::Scalar, ExtendedLagrangeCoeff>>,
|
||||
permutations: Vec<Vec<Polynomial<C::Scalar, LagrangeCoeff>>>,
|
||||
permutation_polys: Vec<Vec<Polynomial<C::Scalar, Coeff>>>,
|
||||
permutation_cosets: Vec<Vec<Polynomial<C::Scalar, ExtendedLagrangeCoeff>>>,
|
||||
permutations: Vec<permutation::ProvingKey<C>>,
|
||||
}
|
||||
|
||||
/// This is an object which represents a (Turbo)PLONK proof.
|
||||
|
|
|
@ -4,7 +4,7 @@ use ff::Field;
|
|||
use std::collections::BTreeMap;
|
||||
use std::convert::TryFrom;
|
||||
|
||||
use super::Error;
|
||||
use super::{permutation, Error};
|
||||
use crate::poly::Rotation;
|
||||
|
||||
/// A column type
|
||||
|
@ -312,7 +312,7 @@ pub struct ConstraintSystem<F> {
|
|||
|
||||
// Vector of permutation arguments, where each corresponds to a sequence of columns
|
||||
// that are involved in a permutation argument.
|
||||
pub(crate) permutations: Vec<Vec<Column<Advice>>>,
|
||||
pub(crate) permutations: Vec<permutation::Argument>,
|
||||
}
|
||||
|
||||
impl<F: Field> Default for ConstraintSystem<F> {
|
||||
|
@ -347,7 +347,8 @@ impl<F: Field> ConstraintSystem<F> {
|
|||
for column in columns {
|
||||
self.query_advice_index(*column, 0);
|
||||
}
|
||||
self.permutations.push(columns.to_vec());
|
||||
self.permutations
|
||||
.push(permutation::Argument::new(columns.to_vec()));
|
||||
|
||||
index
|
||||
}
|
||||
|
|
|
@ -2,9 +2,9 @@ use ff::Field;
|
|||
|
||||
use super::{
|
||||
circuit::{Advice, Assignment, Circuit, Column, ConstraintSystem, Fixed},
|
||||
Error, ProvingKey, VerifyingKey,
|
||||
permutation, Error, ProvingKey, VerifyingKey,
|
||||
};
|
||||
use crate::arithmetic::{Curve, CurveAffine, FieldExt};
|
||||
use crate::arithmetic::{Curve, CurveAffine};
|
||||
use crate::poly::{
|
||||
commitment::{Blind, Params},
|
||||
EvaluationDomain, LagrangeCoeff, Polynomial, Rotation,
|
||||
|
@ -21,9 +21,7 @@ where
|
|||
{
|
||||
struct Assembly<F: Field> {
|
||||
fixed: Vec<Polynomial<F, LagrangeCoeff>>,
|
||||
mapping: Vec<Vec<Vec<(usize, usize)>>>,
|
||||
aux: Vec<Vec<Vec<(usize, usize)>>>,
|
||||
sizes: Vec<Vec<Vec<usize>>>,
|
||||
permutations: permutation::keygen::Assembly,
|
||||
_marker: std::marker::PhantomData<F>,
|
||||
}
|
||||
|
||||
|
@ -61,62 +59,22 @@ where
|
|||
right_column: usize,
|
||||
right_row: usize,
|
||||
) -> Result<(), Error> {
|
||||
// Check bounds first
|
||||
if permutation >= self.mapping.len()
|
||||
|| left_column >= self.mapping[permutation].len()
|
||||
|| left_row >= self.mapping[permutation][left_column].len()
|
||||
|| right_column >= self.mapping[permutation].len()
|
||||
|| right_row >= self.mapping[permutation][right_column].len()
|
||||
{
|
||||
return Err(Error::BoundsFailure);
|
||||
}
|
||||
|
||||
let mut left_cycle = self.aux[permutation][left_column][left_row];
|
||||
let mut right_cycle = self.aux[permutation][right_column][right_row];
|
||||
|
||||
if left_cycle == right_cycle {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if self.sizes[permutation][left_cycle.0][left_cycle.1]
|
||||
< self.sizes[permutation][right_cycle.0][right_cycle.1]
|
||||
{
|
||||
std::mem::swap(&mut left_cycle, &mut right_cycle);
|
||||
}
|
||||
|
||||
self.sizes[permutation][left_cycle.0][left_cycle.1] +=
|
||||
self.sizes[permutation][right_cycle.0][right_cycle.1];
|
||||
let mut i = right_cycle;
|
||||
loop {
|
||||
self.aux[permutation][i.0][i.1] = left_cycle;
|
||||
i = self.mapping[permutation][i.0][i.1];
|
||||
if i == right_cycle {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let tmp = self.mapping[permutation][left_column][left_row];
|
||||
self.mapping[permutation][left_column][left_row] =
|
||||
self.mapping[permutation][right_column][right_row];
|
||||
self.mapping[permutation][right_column][right_row] = tmp;
|
||||
|
||||
Ok(())
|
||||
self.permutations
|
||||
.copy(permutation, left_column, left_row, right_column, right_row)
|
||||
}
|
||||
}
|
||||
|
||||
let mut cs = ConstraintSystem::default();
|
||||
let config = ConcreteCircuit::configure(&mut cs);
|
||||
|
||||
// Get the largest permutation argument length in terms of the number of
|
||||
// advice columns involved.
|
||||
let mut largest_permutation_length = 0;
|
||||
for permutation in &cs.permutations {
|
||||
largest_permutation_length = std::cmp::max(permutation.len(), largest_permutation_length);
|
||||
}
|
||||
|
||||
// The permutation argument will serve alongside the gates, so must be
|
||||
// accounted for.
|
||||
let mut degree = largest_permutation_length + 1;
|
||||
let mut degree = cs
|
||||
.permutations
|
||||
.iter()
|
||||
.map(|p| p.required_degree())
|
||||
.max()
|
||||
.unwrap_or(1);
|
||||
|
||||
// Account for each gate to ensure our quotient polynomial is the
|
||||
// correct degree and that our extended domain is the right size.
|
||||
|
@ -126,95 +84,16 @@ where
|
|||
|
||||
let domain = EvaluationDomain::new(degree as u32, params.k);
|
||||
|
||||
// Compute [omega^0, omega^1, ..., omega^{params.n - 1}]
|
||||
let mut omega_powers = Vec::with_capacity(params.n as usize);
|
||||
{
|
||||
let mut cur = C::Scalar::one();
|
||||
for _ in 0..params.n {
|
||||
omega_powers.push(cur);
|
||||
cur *= &domain.get_omega();
|
||||
}
|
||||
}
|
||||
|
||||
// Compute [omega_powers * \delta^0, omega_powers * \delta^1, ..., omega_powers * \delta^m]
|
||||
let mut deltaomega = Vec::with_capacity(largest_permutation_length);
|
||||
{
|
||||
let mut cur = C::Scalar::one();
|
||||
for _ in 0..largest_permutation_length {
|
||||
let mut omega_powers = omega_powers.clone();
|
||||
for o in &mut omega_powers {
|
||||
*o *= &cur;
|
||||
}
|
||||
|
||||
deltaomega.push(omega_powers);
|
||||
|
||||
cur *= &C::Scalar::DELTA;
|
||||
}
|
||||
}
|
||||
|
||||
let mut assembly: Assembly<C::Scalar> = Assembly {
|
||||
fixed: vec![domain.empty_lagrange(); cs.num_fixed_columns],
|
||||
mapping: vec![],
|
||||
aux: vec![],
|
||||
sizes: vec![],
|
||||
permutations: permutation::keygen::Assembly::new(params, &cs),
|
||||
_marker: std::marker::PhantomData,
|
||||
};
|
||||
|
||||
// Initialize the copy vector to keep track of copy constraints in all
|
||||
// the permutation arguments.
|
||||
for permutation in &cs.permutations {
|
||||
let mut columns = vec![];
|
||||
for i in 0..permutation.len() {
|
||||
// Computes [(i, 0), (i, 1), ..., (i, n - 1)]
|
||||
columns.push((0..params.n).map(|j| (i, j as usize)).collect());
|
||||
}
|
||||
assembly.mapping.push(columns.clone());
|
||||
assembly.aux.push(columns);
|
||||
assembly
|
||||
.sizes
|
||||
.push(vec![vec![1usize; params.n as usize]; permutation.len()]);
|
||||
}
|
||||
|
||||
// Synthesize the circuit to obtain SRS
|
||||
circuit.synthesize(&mut assembly, config)?;
|
||||
|
||||
// Compute permutation polynomials, convert to coset form and
|
||||
// pre-compute commitments for the SRS.
|
||||
let mut permutation_commitments = vec![];
|
||||
let mut permutations = vec![];
|
||||
let mut permutation_polys = vec![];
|
||||
let mut permutation_cosets = vec![];
|
||||
for (permutation_index, permutation) in cs.permutations.iter().enumerate() {
|
||||
let mut commitments = vec![];
|
||||
let mut inner_permutations = vec![];
|
||||
let mut polys = vec![];
|
||||
let mut cosets = vec![];
|
||||
for i in 0..permutation.len() {
|
||||
// Computes the permutation polynomial based on the permutation
|
||||
// description in the assembly.
|
||||
let mut permutation_poly = domain.empty_lagrange();
|
||||
for (j, p) in permutation_poly.iter_mut().enumerate() {
|
||||
let (permuted_i, permuted_j) = assembly.mapping[permutation_index][i][j];
|
||||
*p = deltaomega[permuted_i][permuted_j];
|
||||
}
|
||||
|
||||
// Compute commitment to permutation polynomial
|
||||
commitments.push(
|
||||
params
|
||||
.commit_lagrange(&permutation_poly, Blind::default())
|
||||
.to_affine(),
|
||||
);
|
||||
// Store permutation polynomial and precompute its coset evaluation
|
||||
inner_permutations.push(permutation_poly.clone());
|
||||
let poly = domain.lagrange_to_coeff(permutation_poly);
|
||||
polys.push(poly.clone());
|
||||
cosets.push(domain.coeff_to_extended(poly, Rotation::default()));
|
||||
}
|
||||
permutation_commitments.push(commitments);
|
||||
permutations.push(inner_permutations);
|
||||
permutation_polys.push(polys);
|
||||
permutation_cosets.push(cosets);
|
||||
}
|
||||
let (permutation_pks, permutation_vks) = assembly.permutations.build_keys(params, &cs, &domain);
|
||||
|
||||
let fixed_commitments = assembly
|
||||
.fixed
|
||||
|
@ -248,14 +127,12 @@ where
|
|||
vk: VerifyingKey {
|
||||
domain,
|
||||
fixed_commitments,
|
||||
permutation_commitments,
|
||||
permutations: permutation_vks,
|
||||
cs,
|
||||
},
|
||||
l0,
|
||||
fixed_polys,
|
||||
fixed_cosets,
|
||||
permutations,
|
||||
permutation_polys,
|
||||
permutation_cosets,
|
||||
permutations: permutation_pks,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,10 +1,48 @@
|
|||
//! Implementation of a PLONK permutation argument.
|
||||
|
||||
use crate::arithmetic::CurveAffine;
|
||||
use super::circuit::{Advice, Column};
|
||||
use crate::{
|
||||
arithmetic::CurveAffine,
|
||||
poly::{Coeff, ExtendedLagrangeCoeff, LagrangeCoeff, Polynomial},
|
||||
};
|
||||
|
||||
pub(crate) mod keygen;
|
||||
mod prover;
|
||||
mod verifier;
|
||||
|
||||
/// A permutation argument.
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct Argument {
|
||||
/// A sequence of columns involved in the argument.
|
||||
columns: Vec<Column<Advice>>,
|
||||
}
|
||||
|
||||
impl Argument {
|
||||
pub(crate) fn new(columns: Vec<Column<Advice>>) -> Self {
|
||||
Argument { columns }
|
||||
}
|
||||
|
||||
pub(crate) fn required_degree(&self) -> usize {
|
||||
// The permutation argument will serve alongside the gates, so must be
|
||||
// accounted for.
|
||||
self.columns.len() + 1
|
||||
}
|
||||
}
|
||||
|
||||
/// The verifying key for a single permutation argument.
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct VerifyingKey<C: CurveAffine> {
|
||||
commitments: Vec<C>,
|
||||
}
|
||||
|
||||
/// The proving key for a single permutation argument.
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct ProvingKey<C: CurveAffine> {
|
||||
permutations: Vec<Polynomial<C::Scalar, LagrangeCoeff>>,
|
||||
polys: Vec<Polynomial<C::Scalar, Coeff>>,
|
||||
cosets: Vec<Polynomial<C::Scalar, ExtendedLagrangeCoeff>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct Proof<C: CurveAffine> {
|
||||
permutation_product_commitments: Vec<C>,
|
||||
|
|
|
@ -0,0 +1,179 @@
|
|||
use ff::Field;
|
||||
|
||||
use super::{ProvingKey, VerifyingKey};
|
||||
use crate::{
|
||||
arithmetic::{Curve, CurveAffine, FieldExt},
|
||||
plonk::{circuit::ConstraintSystem, Error},
|
||||
poly::{
|
||||
commitment::{Blind, Params},
|
||||
EvaluationDomain, Rotation,
|
||||
},
|
||||
};
|
||||
|
||||
pub(crate) struct Assembly {
|
||||
mapping: Vec<Vec<Vec<(usize, usize)>>>,
|
||||
aux: Vec<Vec<Vec<(usize, usize)>>>,
|
||||
sizes: Vec<Vec<Vec<usize>>>,
|
||||
}
|
||||
|
||||
impl Assembly {
|
||||
pub(crate) fn new<C: CurveAffine>(
|
||||
params: &Params<C>,
|
||||
cs: &ConstraintSystem<C::Scalar>,
|
||||
) -> Self {
|
||||
let mut assembly = Assembly {
|
||||
mapping: vec![],
|
||||
aux: vec![],
|
||||
sizes: vec![],
|
||||
};
|
||||
|
||||
// Initialize the copy vector to keep track of copy constraints in all
|
||||
// the permutation arguments.
|
||||
for p in &cs.permutations {
|
||||
let mut columns = vec![];
|
||||
for i in 0..p.columns.len() {
|
||||
// Computes [(i, 0), (i, 1), ..., (i, n - 1)]
|
||||
columns.push((0..params.n).map(|j| (i, j as usize)).collect());
|
||||
}
|
||||
assembly.mapping.push(columns.clone());
|
||||
assembly.aux.push(columns);
|
||||
assembly
|
||||
.sizes
|
||||
.push(vec![vec![1usize; params.n as usize]; p.columns.len()]);
|
||||
}
|
||||
|
||||
assembly
|
||||
}
|
||||
|
||||
pub(crate) fn copy(
|
||||
&mut self,
|
||||
permutation: usize,
|
||||
left_column: usize,
|
||||
left_row: usize,
|
||||
right_column: usize,
|
||||
right_row: usize,
|
||||
) -> Result<(), Error> {
|
||||
// Check bounds first
|
||||
if permutation >= self.mapping.len()
|
||||
|| left_column >= self.mapping[permutation].len()
|
||||
|| left_row >= self.mapping[permutation][left_column].len()
|
||||
|| right_column >= self.mapping[permutation].len()
|
||||
|| right_row >= self.mapping[permutation][right_column].len()
|
||||
{
|
||||
return Err(Error::BoundsFailure);
|
||||
}
|
||||
|
||||
let mut left_cycle = self.aux[permutation][left_column][left_row];
|
||||
let mut right_cycle = self.aux[permutation][right_column][right_row];
|
||||
|
||||
if left_cycle == right_cycle {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if self.sizes[permutation][left_cycle.0][left_cycle.1]
|
||||
< self.sizes[permutation][right_cycle.0][right_cycle.1]
|
||||
{
|
||||
std::mem::swap(&mut left_cycle, &mut right_cycle);
|
||||
}
|
||||
|
||||
self.sizes[permutation][left_cycle.0][left_cycle.1] +=
|
||||
self.sizes[permutation][right_cycle.0][right_cycle.1];
|
||||
let mut i = right_cycle;
|
||||
loop {
|
||||
self.aux[permutation][i.0][i.1] = left_cycle;
|
||||
i = self.mapping[permutation][i.0][i.1];
|
||||
if i == right_cycle {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let tmp = self.mapping[permutation][left_column][left_row];
|
||||
self.mapping[permutation][left_column][left_row] =
|
||||
self.mapping[permutation][right_column][right_row];
|
||||
self.mapping[permutation][right_column][right_row] = tmp;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn build_keys<C: CurveAffine>(
|
||||
self,
|
||||
params: &Params<C>,
|
||||
cs: &ConstraintSystem<C::Scalar>,
|
||||
domain: &EvaluationDomain<C::Scalar>,
|
||||
) -> (Vec<ProvingKey<C>>, Vec<VerifyingKey<C>>) {
|
||||
// Get the largest permutation argument length in terms of the number of
|
||||
// advice columns involved.
|
||||
let largest_permutation_length = cs
|
||||
.permutations
|
||||
.iter()
|
||||
.map(|p| p.columns.len())
|
||||
.max()
|
||||
.unwrap_or_default();
|
||||
|
||||
// Compute [omega^0, omega^1, ..., omega^{params.n - 1}]
|
||||
let mut omega_powers = Vec::with_capacity(params.n as usize);
|
||||
{
|
||||
let mut cur = C::Scalar::one();
|
||||
for _ in 0..params.n {
|
||||
omega_powers.push(cur);
|
||||
cur *= &domain.get_omega();
|
||||
}
|
||||
}
|
||||
|
||||
// Compute [omega_powers * \delta^0, omega_powers * \delta^1, ..., omega_powers * \delta^m]
|
||||
let mut deltaomega = Vec::with_capacity(largest_permutation_length);
|
||||
{
|
||||
let mut cur = C::Scalar::one();
|
||||
for _ in 0..largest_permutation_length {
|
||||
let mut omega_powers = omega_powers.clone();
|
||||
for o in &mut omega_powers {
|
||||
*o *= &cur;
|
||||
}
|
||||
|
||||
deltaomega.push(omega_powers);
|
||||
|
||||
cur *= &C::Scalar::DELTA;
|
||||
}
|
||||
}
|
||||
|
||||
// Compute permutation polynomials, convert to coset form and
|
||||
// pre-compute commitments for the SRS.
|
||||
let mut pks = vec![];
|
||||
let mut vks = vec![];
|
||||
for (p, mapping) in cs.permutations.iter().zip(self.mapping.iter()) {
|
||||
let mut commitments = vec![];
|
||||
let mut permutations = vec![];
|
||||
let mut polys = vec![];
|
||||
let mut cosets = vec![];
|
||||
for i in 0..p.columns.len() {
|
||||
// Computes the permutation polynomial based on the permutation
|
||||
// description in the assembly.
|
||||
let mut permutation_poly = domain.empty_lagrange();
|
||||
for (j, p) in permutation_poly.iter_mut().enumerate() {
|
||||
let (permuted_i, permuted_j) = mapping[i][j];
|
||||
*p = deltaomega[permuted_i][permuted_j];
|
||||
}
|
||||
|
||||
// Compute commitment to permutation polynomial
|
||||
commitments.push(
|
||||
params
|
||||
.commit_lagrange(&permutation_poly, Blind::default())
|
||||
.to_affine(),
|
||||
);
|
||||
// Store permutation polynomial and precompute its coset evaluation
|
||||
permutations.push(permutation_poly.clone());
|
||||
let poly = domain.lagrange_to_coeff(permutation_poly);
|
||||
polys.push(poly.clone());
|
||||
cosets.push(domain.coeff_to_extended(poly, Rotation::default()));
|
||||
}
|
||||
vks.push(VerifyingKey { commitments });
|
||||
pks.push(ProvingKey {
|
||||
permutations,
|
||||
polys,
|
||||
cosets,
|
||||
});
|
||||
}
|
||||
|
||||
(pks, vks)
|
||||
}
|
||||
}
|
|
@ -67,11 +67,12 @@ impl<C: CurveAffine> Proof<C> {
|
|||
//
|
||||
// where p_j(X) is the jth advice column in this permutation,
|
||||
// and i is the ith row of the column.
|
||||
.map(|(columns, permuted_values)| {
|
||||
.map(|(p, pkey)| {
|
||||
let mut modified_advice = vec![C::Scalar::one(); params.n as usize];
|
||||
|
||||
// Iterate over each column of the permutation
|
||||
for (&column, permuted_column_values) in columns.iter().zip(permuted_values.iter())
|
||||
for (&column, permuted_column_values) in
|
||||
p.columns.iter().zip(pkey.permutations.iter())
|
||||
{
|
||||
parallelize(&mut modified_advice, |modified_advice, start| {
|
||||
for ((modified_advice, advice_value), permuted_advice_value) in
|
||||
|
@ -97,7 +98,7 @@ impl<C: CurveAffine> Proof<C> {
|
|||
.flat_map(|v| v.iter_mut())
|
||||
.batch_invert();
|
||||
|
||||
for (columns, mut modified_advice) in pk
|
||||
for (p, mut modified_advice) in pk
|
||||
.vk
|
||||
.cs
|
||||
.permutations
|
||||
|
@ -107,7 +108,7 @@ impl<C: CurveAffine> Proof<C> {
|
|||
// Iterate over each column again, this time finishing the computation
|
||||
// of the entire fraction by computing the numerators
|
||||
let mut deltaomega = C::Scalar::one();
|
||||
for &column in columns.iter() {
|
||||
for &column in p.columns.iter() {
|
||||
let omega = domain.get_omega();
|
||||
parallelize(&mut modified_advice, |modified_advice, start| {
|
||||
let mut deltaomega = deltaomega * &omega.pow_vartime(&[start as u64, 0, 0, 0]);
|
||||
|
@ -195,8 +196,8 @@ impl<C: CurveAffine> Committed<C> {
|
|||
> {
|
||||
let domain = &pk.vk.domain;
|
||||
let permutation_product_cosets_owned = self.permutation_product_cosets.clone();
|
||||
let permutation_product_cosets = self.permutation_product_cosets;
|
||||
let permutation_product_cosets_inv = self.permutation_product_cosets_inv;
|
||||
let permutation_product_cosets = self.permutation_product_cosets.clone();
|
||||
let permutation_product_cosets_inv = self.permutation_product_cosets_inv.clone();
|
||||
|
||||
let expressions = iter::empty()
|
||||
// l_0(X) * (1 - z(X)) = 0
|
||||
|
@ -206,46 +207,56 @@ impl<C: CurveAffine> Committed<C> {
|
|||
.map(move |coset| Polynomial::one_minus(coset) * &pk.l0),
|
||||
)
|
||||
// z(X) \prod (p(X) + \beta s_i(X) + \gamma) - z(omega^{-1} X) \prod (p(X) + \delta^i \beta X + \gamma)
|
||||
.chain(pk.vk.cs.permutations.iter().enumerate().map(
|
||||
move |(permutation_index, columns)| {
|
||||
let mut left = permutation_product_cosets[permutation_index].clone();
|
||||
for (advice, permutation) in columns
|
||||
.iter()
|
||||
.map(|&column| &advice_cosets[pk.vk.cs.get_advice_query_index(column, 0)])
|
||||
.zip(pk.permutation_cosets[permutation_index].iter())
|
||||
{
|
||||
parallelize(&mut left, |left, start| {
|
||||
for ((left, advice), permutation) in left
|
||||
.iter_mut()
|
||||
.zip(advice[start..].iter())
|
||||
.zip(permutation[start..].iter())
|
||||
{
|
||||
*left *= &(*advice + &(*beta * permutation) + &gamma);
|
||||
}
|
||||
});
|
||||
}
|
||||
.chain(
|
||||
pk.vk
|
||||
.cs
|
||||
.permutations
|
||||
.iter()
|
||||
.zip(pk.permutations.iter())
|
||||
.zip(permutation_product_cosets.into_iter())
|
||||
.zip(permutation_product_cosets_inv.into_iter())
|
||||
.map(move |(((p, pkey), cosets), cosets_inv)| {
|
||||
let mut left = cosets;
|
||||
for (advice, permutation) in p
|
||||
.columns
|
||||
.iter()
|
||||
.map(|&column| {
|
||||
&advice_cosets[pk.vk.cs.get_advice_query_index(column, 0)]
|
||||
})
|
||||
.zip(pkey.cosets.iter())
|
||||
{
|
||||
parallelize(&mut left, |left, start| {
|
||||
for ((left, advice), permutation) in left
|
||||
.iter_mut()
|
||||
.zip(advice[start..].iter())
|
||||
.zip(permutation[start..].iter())
|
||||
{
|
||||
*left *= &(*advice + &(*beta * permutation) + &gamma);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let mut right = permutation_product_cosets_inv[permutation_index].clone();
|
||||
let mut current_delta = *beta * &C::Scalar::ZETA;
|
||||
let step = domain.get_extended_omega();
|
||||
for advice in columns
|
||||
.iter()
|
||||
.map(|&column| &advice_cosets[pk.vk.cs.get_advice_query_index(column, 0)])
|
||||
{
|
||||
parallelize(&mut right, move |right, start| {
|
||||
let mut beta_term =
|
||||
current_delta * &step.pow_vartime(&[start as u64, 0, 0, 0]);
|
||||
for (right, advice) in right.iter_mut().zip(advice[start..].iter()) {
|
||||
*right *= &(*advice + &beta_term + &gamma);
|
||||
beta_term *= &step;
|
||||
}
|
||||
});
|
||||
current_delta *= &C::Scalar::DELTA;
|
||||
}
|
||||
let mut right = cosets_inv;
|
||||
let mut current_delta = *beta * &C::Scalar::ZETA;
|
||||
let step = domain.get_extended_omega();
|
||||
for advice in p.columns.iter().map(|&column| {
|
||||
&advice_cosets[pk.vk.cs.get_advice_query_index(column, 0)]
|
||||
}) {
|
||||
parallelize(&mut right, move |right, start| {
|
||||
let mut beta_term =
|
||||
current_delta * &step.pow_vartime(&[start as u64, 0, 0, 0]);
|
||||
for (right, advice) in right.iter_mut().zip(advice[start..].iter())
|
||||
{
|
||||
*right *= &(*advice + &beta_term + &gamma);
|
||||
beta_term *= &step;
|
||||
}
|
||||
});
|
||||
current_delta *= &C::Scalar::DELTA;
|
||||
}
|
||||
|
||||
left - &right
|
||||
},
|
||||
));
|
||||
left - &right
|
||||
}),
|
||||
);
|
||||
|
||||
Ok((
|
||||
Constructed {
|
||||
|
@ -258,6 +269,31 @@ impl<C: CurveAffine> Committed<C> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<C: CurveAffine> super::ProvingKey<C> {
|
||||
fn evaluate(&self, x: ChallengeX<C::Scalar>) -> Vec<C::Scalar> {
|
||||
self.polys
|
||||
.iter()
|
||||
.map(|poly| eval_polynomial(poly, *x))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn open<'a>(
|
||||
&'a self,
|
||||
evals: &'a [C::Scalar],
|
||||
x: ChallengeX<C::Scalar>,
|
||||
) -> impl Iterator<Item = ProverQuery<'a, C>> + Clone {
|
||||
self.polys
|
||||
.iter()
|
||||
.zip(evals.iter())
|
||||
.map(move |(poly, eval)| ProverQuery {
|
||||
point: *x,
|
||||
poly,
|
||||
blind: Blind::default(),
|
||||
eval: *eval,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: CurveAffine> Constructed<C> {
|
||||
pub(crate) fn evaluate<HBase: Hasher<C::Base>, HScalar: Hasher<C::Scalar>>(
|
||||
self,
|
||||
|
@ -279,11 +315,7 @@ impl<C: CurveAffine> Constructed<C> {
|
|||
.map(|poly| eval_polynomial(poly, domain.rotate_omega(*x, Rotation(-1))))
|
||||
.collect();
|
||||
|
||||
let permutation_evals: Vec<Vec<C::Scalar>> = pk
|
||||
.permutation_polys
|
||||
.iter()
|
||||
.map(|polys| polys.iter().map(|poly| eval_polynomial(poly, *x)).collect())
|
||||
.collect();
|
||||
let permutation_evals: Vec<_> = pk.permutations.iter().map(|p| p.evaluate(x)).collect();
|
||||
|
||||
// Hash each advice evaluation
|
||||
for eval in permutation_product_evals
|
||||
|
@ -328,16 +360,10 @@ impl<C: CurveAffine> Evaluated<C> {
|
|||
)
|
||||
// Open permutation polynomial commitments at x
|
||||
.chain(
|
||||
pk.permutation_polys
|
||||
pk.permutations
|
||||
.iter()
|
||||
.zip(self.permutation_evals.iter())
|
||||
.flat_map(|(polys, evals)| polys.iter().zip(evals.iter()))
|
||||
.map(move |(poly, eval)| ProverQuery {
|
||||
point: *x,
|
||||
poly,
|
||||
blind: Blind::default(),
|
||||
eval: *eval,
|
||||
}),
|
||||
.flat_map(move |(permutation, evals)| permutation.open(evals, x)),
|
||||
)
|
||||
// Open permutation product commitments at \omega^{-1} x
|
||||
.chain(
|
||||
|
|
|
@ -15,10 +15,8 @@ impl<C: CurveAffine> Proof<C> {
|
|||
return Err(Error::IncompatibleParams);
|
||||
}
|
||||
|
||||
for (permutation_evals, permutation) in
|
||||
self.permutation_evals.iter().zip(vk.cs.permutations.iter())
|
||||
{
|
||||
if permutation_evals.len() != permutation.len() {
|
||||
for (permutation_evals, p) in self.permutation_evals.iter().zip(vk.cs.permutations.iter()) {
|
||||
if permutation_evals.len() != p.columns.len() {
|
||||
return Err(Error::IncompatibleParams);
|
||||
}
|
||||
}
|
||||
|
@ -76,9 +74,10 @@ impl<C: CurveAffine> Proof<C> {
|
|||
.zip(self.permutation_product_evals.iter())
|
||||
.zip(self.permutation_product_inv_evals.iter())
|
||||
.map(
|
||||
move |(((columns, permutation_evals), product_eval), product_inv_eval)| {
|
||||
move |(((p, permutation_evals), product_eval), product_inv_eval)| {
|
||||
let mut left = *product_eval;
|
||||
for (advice_eval, permutation_eval) in columns
|
||||
for (advice_eval, permutation_eval) in p
|
||||
.columns
|
||||
.iter()
|
||||
.map(|&column| {
|
||||
advice_evals[vk.cs.get_advice_query_index(column, 0)]
|
||||
|
@ -90,7 +89,7 @@ impl<C: CurveAffine> Proof<C> {
|
|||
|
||||
let mut right = *product_inv_eval;
|
||||
let mut current_delta = *beta * &x;
|
||||
for advice_eval in columns.iter().map(|&column| {
|
||||
for advice_eval in p.columns.iter().map(|&column| {
|
||||
advice_evals[vk.cs.get_advice_query_index(column, 0)]
|
||||
}) {
|
||||
right *= &(advice_eval + ¤t_delta + &gamma);
|
||||
|
@ -132,12 +131,12 @@ impl<C: CurveAffine> Proof<C> {
|
|||
)
|
||||
// Open permutation commitments for each permutation argument at x
|
||||
.chain(
|
||||
(0..vk.permutation_commitments.len())
|
||||
(0..vk.permutations.len())
|
||||
.map(move |outer_idx| {
|
||||
let inner_len = vk.permutation_commitments[outer_idx].len();
|
||||
let inner_len = vk.permutations[outer_idx].commitments.len();
|
||||
(0..inner_len).map(move |inner_idx| VerifierQuery {
|
||||
point: *x,
|
||||
commitment: &vk.permutation_commitments[outer_idx][inner_idx],
|
||||
commitment: &vk.permutations[outer_idx].commitments[inner_idx],
|
||||
eval: self.permutation_evals[outer_idx][inner_idx],
|
||||
})
|
||||
})
|
||||
|
|
Loading…
Reference in New Issue