diff --git a/src/plonk/keygen.rs b/src/plonk/keygen.rs index c04fd42..984dca6 100644 --- a/src/plonk/keygen.rs +++ b/src/plonk/keygen.rs @@ -21,7 +21,7 @@ where { struct Assembly { fixed: Vec>, - permutations: permutation::keygen::Assembly, + permutations: Vec, _marker: std::marker::PhantomData, } @@ -59,8 +59,12 @@ where right_column: usize, right_row: usize, ) -> Result<(), Error> { - self.permutations - .copy(permutation, left_column, left_row, right_column, right_row) + // Check bounds first + if permutation >= self.permutations.len() { + return Err(Error::BoundsFailure); + } + + self.permutations[permutation].copy(left_column, left_row, right_column, right_row) } } @@ -97,14 +101,25 @@ where let mut assembly: Assembly = Assembly { fixed: vec![domain.empty_lagrange(); cs.num_fixed_columns], - permutations: permutation::keygen::Assembly::new(params, &cs), + permutations: cs + .permutations + .iter() + .map(|p| permutation::keygen::Assembly::new(params, p)) + .collect(), _marker: std::marker::PhantomData, }; // Synthesize the circuit to obtain SRS circuit.synthesize(&mut assembly, config)?; - let (permutation_pks, permutation_vks) = assembly.permutations.build_keys(params, &cs, &domain); + let permutation_helper = permutation::keygen::Assembly::build_helper(params, &cs, &domain); + + let (permutation_pks, permutation_vks) = cs + .permutations + .iter() + .zip(assembly.permutations.into_iter()) + .map(|(p, assembly)| assembly.build_keys(params, &domain, &permutation_helper, p)) + .unzip(); let fixed_commitments = assembly .fixed diff --git a/src/plonk/permutation/keygen.rs b/src/plonk/permutation/keygen.rs index 960cb04..d5bfadd 100644 --- a/src/plonk/permutation/keygen.rs +++ b/src/plonk/permutation/keygen.rs @@ -1,6 +1,6 @@ use ff::Field; -use super::{ProvingKey, VerifyingKey}; +use super::{Argument, ProvingKey, VerifyingKey}; use crate::{ arithmetic::{Curve, CurveAffine, FieldExt}, plonk::{circuit::ConstraintSystem, Error}, @@ -10,97 +10,82 @@ use crate::{ }, }; +pub(crate) struct AssemblyHelper { + deltaomega: Vec>, +} + pub(crate) struct Assembly { - mapping: Vec>>, - aux: Vec>>, - sizes: Vec>>, + mapping: Vec>, + aux: Vec>, + sizes: Vec>, } impl Assembly { - pub(crate) fn new( - params: &Params, - cs: &ConstraintSystem, - ) -> Self { - let mut assembly = Assembly { - mapping: vec![], - aux: vec![], - sizes: vec![], - }; - + pub(crate) fn new(params: &Params, p: &Argument) -> Self { // 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()]); + 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 + Assembly { + mapping: columns.clone(), + aux: columns, + sizes: vec![vec![1usize; params.n as usize]; p.columns.len()], + } } 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() + if left_column >= self.mapping.len() + || left_row >= self.mapping[left_column].len() + || right_column >= self.mapping.len() + || right_row >= self.mapping[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]; + let mut left_cycle = self.aux[left_column][left_row]; + let mut right_cycle = self.aux[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] - { + if self.sizes[left_cycle.0][left_cycle.1] < self.sizes[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]; + self.sizes[left_cycle.0][left_cycle.1] += self.sizes[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]; + self.aux[i.0][i.1] = left_cycle; + i = self.mapping[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; + let tmp = self.mapping[left_column][left_row]; + self.mapping[left_column][left_row] = self.mapping[right_column][right_row]; + self.mapping[right_column][right_row] = tmp; Ok(()) } - pub(crate) fn build_keys( - self, + pub(crate) fn build_helper( params: &Params, cs: &ConstraintSystem, domain: &EvaluationDomain, - ) -> (Vec>, Vec>) { + ) -> AssemblyHelper { // Get the largest permutation argument length in terms of the number of // advice columns involved. let largest_permutation_length = cs @@ -136,44 +121,50 @@ impl Assembly { } } + AssemblyHelper { deltaomega } + } + + pub(crate) fn build_keys( + self, + params: &Params, + domain: &EvaluationDomain, + helper: &AssemblyHelper, + p: &Argument, + ) -> (ProvingKey, VerifyingKey) { // 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())); + 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) = self.mapping[i][j]; + *p = helper.deltaomega[permuted_i][permuted_j]; } - vks.push(VerifyingKey { commitments }); - pks.push(ProvingKey { + + // 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())); + } + ( + ProvingKey { permutations, polys, cosets, - }); - } - - (pks, vks) + }, + VerifyingKey { commitments }, + ) } }