From 02b5b8442b48388d669812c3ee6f4fcd7b1d0702 Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Wed, 20 Jan 2021 21:47:55 +0800 Subject: [PATCH 1/5] Refactor PLONK prover --- src/plonk/circuit.rs | 2 +- src/plonk/lookup.rs | 4 +- src/plonk/permutation.rs | 4 +- src/plonk/prover.rs | 676 ++++++++++++++++++++++++--------------- 4 files changed, 430 insertions(+), 256 deletions(-) diff --git a/src/plonk/circuit.rs b/src/plonk/circuit.rs index 33feaf7..25d97c1 100644 --- a/src/plonk/circuit.rs +++ b/src/plonk/circuit.rs @@ -158,7 +158,7 @@ pub trait Assignment { /// [`ConstraintSystem`] implementation. pub trait Circuit { /// This is a configuration object that stores things like columns. - type Config; + type Config: Copy; /// The circuit is given an opportunity to describe the exact gate /// arrangement, column arrangement, etc. diff --git a/src/plonk/lookup.rs b/src/plonk/lookup.rs index 1f05569..acb76ff 100644 --- a/src/plonk/lookup.rs +++ b/src/plonk/lookup.rs @@ -1,7 +1,7 @@ use super::circuit::{Any, Column}; -mod prover; -mod verifier; +pub(crate) mod prover; +pub(crate) mod verifier; #[derive(Clone, Debug)] pub(crate) struct Argument { diff --git a/src/plonk/permutation.rs b/src/plonk/permutation.rs index 86cf917..89f178d 100644 --- a/src/plonk/permutation.rs +++ b/src/plonk/permutation.rs @@ -7,8 +7,8 @@ use crate::{ }; pub(crate) mod keygen; -mod prover; -mod verifier; +pub(crate) mod prover; +pub(crate) mod verifier; use std::io; diff --git a/src/plonk/prover.rs b/src/plonk/prover.rs index a7f1118..0514147 100644 --- a/src/plonk/prover.rs +++ b/src/plonk/prover.rs @@ -3,14 +3,14 @@ use std::iter; use super::{ circuit::{Advice, Assignment, Circuit, Column, ConstraintSystem, Fixed}, - vanishing, ChallengeBeta, ChallengeGamma, ChallengeTheta, ChallengeX, ChallengeY, Error, - ProvingKey, + lookup, permutation, vanishing, ChallengeBeta, ChallengeGamma, ChallengeTheta, ChallengeX, + ChallengeY, Error, ProvingKey, }; use crate::arithmetic::{eval_polynomial, Curve, CurveAffine, FieldExt}; use crate::poly::{ commitment::{Blind, Params}, multiopen::{self, ProverQuery}, - LagrangeCoeff, Polynomial, + Coeff, ExtendedLagrangeCoeff, LagrangeCoeff, Polynomial, }; use crate::transcript::TranscriptWrite; @@ -20,50 +20,13 @@ use crate::transcript::TranscriptWrite; pub fn create_proof, ConcreteCircuit: Circuit>( params: &Params, pk: &ProvingKey, - circuit: &ConcreteCircuit, - aux: &[Polynomial], + circuits: &[ConcreteCircuit], + auxs: &[&[Polynomial]], transcript: &mut T, ) -> Result<(), Error> { - if aux.len() != pk.vk.cs.num_aux_columns { - return Err(Error::IncompatibleParams); - } - - struct WitnessCollection { - advice: Vec>, - _marker: std::marker::PhantomData, - } - - impl Assignment for WitnessCollection { - fn assign_advice( - &mut self, - column: Column, - row: usize, - to: impl FnOnce() -> Result, - ) -> Result<(), Error> { - *self - .advice - .get_mut(column.index()) - .and_then(|v| v.get_mut(row)) - .ok_or(Error::BoundsFailure)? = to()?; - - Ok(()) - } - - fn assign_fixed( - &mut self, - _: Column, - _: usize, - _: impl FnOnce() -> Result, - ) -> Result<(), Error> { - // We only care about advice columns here - - Ok(()) - } - - fn copy(&mut self, _: usize, _: usize, _: usize, _: usize, _: usize) -> Result<(), Error> { - // We only care about advice columns here - - Ok(()) + for aux in auxs.iter() { + if aux.len() != pk.vk.cs.num_aux_columns { + return Err(Error::IncompatibleParams); } } @@ -71,115 +34,218 @@ pub fn create_proof, ConcreteCircuit: Circ let mut meta = ConstraintSystem::default(); let config = ConcreteCircuit::configure(&mut meta); - let mut witness = WitnessCollection { - advice: vec![domain.empty_lagrange(); meta.num_advice_columns], - _marker: std::marker::PhantomData, + struct AuxSingle { + pub aux_values: Vec>, + pub aux_polys: Vec>, + pub aux_cosets: Vec>, + } + + let aux_vec: Result, _> = auxs + .iter() + .map(|aux| -> Result, Error> { + let aux_commitments_projective: Vec<_> = aux + .iter() + .map(|poly| params.commit_lagrange(poly, Blind::default())) + .collect(); + let mut aux_commitments = vec![C::zero(); aux_commitments_projective.len()]; + C::Projective::batch_to_affine(&aux_commitments_projective, &mut aux_commitments); + let aux_commitments = aux_commitments; + drop(aux_commitments_projective); + metrics::counter!("aux_commitments", aux_commitments.len() as u64); + + for commitment in &aux_commitments { + transcript + .common_point(*commitment) + .map_err(|_| Error::TranscriptError)?; + } + + let aux_polys: Vec<_> = aux + .iter() + .map(|poly| { + let lagrange_vec = domain.lagrange_from_vec(poly.to_vec()); + domain.lagrange_to_coeff(lagrange_vec) + }) + .collect(); + + let aux_cosets: Vec<_> = meta + .aux_queries + .iter() + .map(|&(column, at)| { + let poly = aux_polys[column.index()].clone(); + domain.coeff_to_extended(poly, at) + }) + .collect(); + + Ok(AuxSingle { + aux_values: aux.to_vec(), + aux_polys, + aux_cosets, + }) + }) + .collect(); + + let aux_vec = match aux_vec { + Ok(aux_vec) => aux_vec, + Err(err) => return Err(err), }; - // Synthesize the circuit to obtain the witness and other information. - circuit.synthesize(&mut witness, config)?; - - let witness = witness; - - // Compute commitments to aux column polynomials - let aux_commitments_projective: Vec<_> = aux - .iter() - .map(|poly| params.commit_lagrange(poly, Blind::default())) - .collect(); - let mut aux_commitments = vec![C::zero(); aux_commitments_projective.len()]; - C::Projective::batch_to_affine(&aux_commitments_projective, &mut aux_commitments); - let aux_commitments = aux_commitments; - drop(aux_commitments_projective); - metrics::counter!("aux_commitments", aux_commitments.len() as u64); - - for commitment in &aux_commitments { - transcript - .common_point(*commitment) - .map_err(|_| Error::TranscriptError)?; + struct AdviceSingle { + pub advice_values: Vec>, + pub advice_polys: Vec>, + pub advice_cosets: Vec>, + pub advice_blinds: Vec>, } - let aux_polys: Vec<_> = aux + let advice_vec: Result, _> = circuits .iter() - .map(|poly| { - let lagrange_vec = domain.lagrange_from_vec(poly.to_vec()); - domain.lagrange_to_coeff(lagrange_vec) + .map(|circuit| -> Result, Error> { + struct WitnessCollection { + pub advice: Vec>, + _marker: std::marker::PhantomData, + } + + impl Assignment for WitnessCollection { + fn assign_advice( + &mut self, + column: Column, + row: usize, + to: impl FnOnce() -> Result, + ) -> Result<(), Error> { + *self + .advice + .get_mut(column.index()) + .and_then(|v| v.get_mut(row)) + .ok_or(Error::BoundsFailure)? = to()?; + + Ok(()) + } + + fn assign_fixed( + &mut self, + _: Column, + _: usize, + _: impl FnOnce() -> Result, + ) -> Result<(), Error> { + // We only care about advice columns here + + Ok(()) + } + + fn copy( + &mut self, + _: usize, + _: usize, + _: usize, + _: usize, + _: usize, + ) -> Result<(), Error> { + // We only care about advice columns here + + Ok(()) + } + } + + let mut witness = WitnessCollection { + advice: vec![domain.empty_lagrange(); meta.num_advice_columns], + _marker: std::marker::PhantomData, + }; + + // Synthesize the circuit to obtain the witness and other information. + circuit.synthesize(&mut witness, config)?; + + let witness = witness; + + // Compute commitments to advice column polynomials + let advice_blinds: Vec<_> = witness + .advice + .iter() + .map(|_| Blind(C::Scalar::rand())) + .collect(); + let advice_commitments_projective: Vec<_> = witness + .advice + .iter() + .zip(advice_blinds.iter()) + .map(|(poly, blind)| params.commit_lagrange(poly, *blind)) + .collect(); + let mut advice_commitments = vec![C::zero(); advice_commitments_projective.len()]; + C::Projective::batch_to_affine(&advice_commitments_projective, &mut advice_commitments); + let advice_commitments = advice_commitments; + drop(advice_commitments_projective); + metrics::counter!("advice_commitments", advice_commitments.len() as u64); + + for commitment in &advice_commitments { + transcript + .write_point(*commitment) + .map_err(|_| Error::TranscriptError)?; + } + + let advice_polys: Vec<_> = witness + .advice + .clone() + .into_iter() + .map(|poly| domain.lagrange_to_coeff(poly)) + .collect(); + + let advice_cosets: Vec<_> = meta + .advice_queries + .iter() + .map(|&(column, at)| { + let poly = advice_polys[column.index()].clone(); + domain.coeff_to_extended(poly, at) + }) + .collect(); + + Ok(AdviceSingle { + advice_values: witness.advice, + advice_polys, + advice_cosets, + advice_blinds, + }) }) .collect(); - let aux_cosets: Vec<_> = meta - .aux_queries - .iter() - .map(|&(column, at)| { - let poly = aux_polys[column.index()].clone(); - domain.coeff_to_extended(poly, at) - }) - .collect(); - - // Compute commitments to advice column polynomials - let advice_blinds: Vec<_> = witness - .advice - .iter() - .map(|_| Blind(C::Scalar::rand())) - .collect(); - let advice_commitments_projective: Vec<_> = witness - .advice - .iter() - .zip(advice_blinds.iter()) - .map(|(poly, blind)| params.commit_lagrange(poly, *blind)) - .collect(); - let mut advice_commitments = vec![C::zero(); advice_commitments_projective.len()]; - C::Projective::batch_to_affine(&advice_commitments_projective, &mut advice_commitments); - let advice_commitments = advice_commitments; - drop(advice_commitments_projective); - metrics::counter!("advice_commitments", advice_commitments.len() as u64); - - for commitment in &advice_commitments { - transcript - .write_point(*commitment) - .map_err(|_| Error::TranscriptError)?; - } - - let advice_polys: Vec<_> = witness - .advice - .clone() - .into_iter() - .map(|poly| domain.lagrange_to_coeff(poly)) - .collect(); - - let advice_cosets: Vec<_> = meta - .advice_queries - .iter() - .map(|&(column, at)| { - let poly = advice_polys[column.index()].clone(); - domain.coeff_to_extended(poly, at) - }) - .collect(); + let advice_vec = match advice_vec { + Ok(advice_vec) => advice_vec, + Err(err) => return Err(err), + }; // Sample theta challenge for keeping lookup columns linearly independent let theta = ChallengeTheta::get(transcript); - // Construct and commit to permuted values for each lookup - let lookups = pk - .vk - .cs - .lookups + let lookups_vec: Result>, _> = aux_vec .iter() - .map(|lookup| { - lookup.commit_permuted( - &pk, - ¶ms, - &domain, - theta, - &witness.advice, - &pk.fixed_values, - &aux, - &advice_cosets, - &pk.fixed_cosets, - &aux_cosets, - transcript, - ) - }) - .collect::, _>>()?; + .zip(advice_vec.iter()) + .map( + |(aux, advice)| -> Result>, Error> { + // Construct and commit to permuted values for each lookup + pk.vk + .cs + .lookups + .iter() + .map(|lookup| { + lookup.commit_permuted( + &pk, + ¶ms, + &domain, + theta, + &advice.advice_values, + &pk.fixed_values, + &aux.aux_values, + &advice.advice_cosets, + &pk.fixed_cosets, + &aux.aux_cosets, + transcript, + ) + }) + .collect() + }, + ) + .collect(); + + let lookups_vec = match lookups_vec { + Ok(lookups_vec) => lookups_vec, + Err(err) => return Err(err), + }; // Sample beta challenge let beta = ChallengeBeta::get(transcript); @@ -187,89 +253,166 @@ pub fn create_proof, ConcreteCircuit: Circ // Sample gamma challenge let gamma = ChallengeGamma::get(transcript); - // Commit to permutations, if any. - let permutations = pk - .vk - .cs - .permutations + let permutations_vec: Result>, _> = advice_vec .iter() - .zip(pk.permutations.iter()) - .map(|(p, pkey)| p.commit(params, pk, pkey, &witness.advice, beta, gamma, transcript)) - .collect::, _>>()?; + .map( + |advice| -> Result>, Error> { + // Commit to permutations, if any. + pk.vk + .cs + .permutations + .iter() + .zip(pk.permutations.iter()) + .map(|(p, pkey)| { + p.commit( + params, + pk, + pkey, + &advice.advice_values, + beta, + gamma, + transcript, + ) + }) + .collect() + }, + ) + .collect(); - // Construct and commit to products for each lookup - let lookups = lookups + let permutations_vec = match permutations_vec { + Ok(permutations_vec) => permutations_vec, + Err(err) => return Err(err), + }; + + let lookups_vec: Result>>, _> = lookups_vec .into_iter() - .map(|lookup| lookup.commit_product(&pk, ¶ms, theta, beta, gamma, transcript)) - .collect::, _>>()?; + .map(|lookups| -> Result, _> { + // Construct and commit to products for each lookup + lookups + .into_iter() + .map(|lookup| lookup.commit_product(&pk, ¶ms, theta, beta, gamma, transcript)) + .collect::, _>>() + }) + .collect(); + + let lookups_vec = match lookups_vec { + Ok(lookups_vec) => lookups_vec, + Err(err) => return Err(err), + }; // Obtain challenge for keeping all separate gates linearly independent let y = ChallengeY::get(transcript); - // Evaluate the h(X) polynomial's constraint system expressions for the permutation constraints, if any. - let (permutations, permutation_expressions): (Vec<_>, Vec<_>) = { - let tmp: Vec<_> = permutations + let (permutations_vec, permutation_expressions_vec): (Vec>, Vec>) = + permutations_vec .into_iter() - .zip(pk.vk.cs.permutations.iter()) - .zip(pk.permutations.iter()) - .map(|((p, argument), pkey)| { - p.construct(pk, argument, pkey, &advice_cosets, beta, gamma) + .zip(advice_vec.iter()) + .map(|(permutations, advice)| { + let tmp: Vec<_> = permutations + .into_iter() + .zip(pk.vk.cs.permutations.iter()) + .zip(pk.permutations.iter()) + .map(|((p, argument), pkey)| { + p.construct(pk, argument, pkey, &advice.advice_cosets, beta, gamma) + }) + .collect(); + + tmp.into_iter().unzip() }) - .collect(); - - tmp.into_iter().unzip() - }; - - // Evaluate the h(X) polynomial's constraint system expressions for the lookup constraints, if any. - let (lookups, lookup_expressions): (Vec<_>, Vec<_>) = { - let tmp: Vec<_> = lookups + .collect::, Vec<_>)>>() .into_iter() - .map(|p| p.construct(pk, theta, beta, gamma)) - .collect(); + .unzip(); - tmp.into_iter().unzip() - }; + let (lookups_vec, lookup_expressions_vec): (Vec>, Vec>) = lookups_vec + .into_iter() + .map(|lookups| { + // Evaluate the h(X) polynomial's constraint system expressions for the lookup constraints, if any. + let tmp: Vec<_> = lookups + .into_iter() + .map(|p| p.construct(pk, theta, beta, gamma)) + .collect(); - // Evaluate the h(X) polynomial's constraint system expressions for the constraints provided - let expressions = iter::empty() - // Custom constraints - .chain(meta.gates.iter().map(|poly| { - poly.evaluate( - &|index| pk.fixed_cosets[index].clone(), - &|index| advice_cosets[index].clone(), - &|index| aux_cosets[index].clone(), - &|a, b| a + &b, - &|a, b| a * &b, - &|a, scalar| a * scalar, - ) - })) - // Permutation constraints, if any. - .chain(permutation_expressions.into_iter().flatten()) - // Lookup constraints, if any. - .chain(lookup_expressions.into_iter().flatten()); + tmp.into_iter().unzip() + }) + .collect::, Vec<_>)>>() + .into_iter() + .unzip(); + + let expressions = advice_vec + .iter() + .zip(aux_vec.iter()) + .zip(permutation_expressions_vec.into_iter()) + .zip(lookup_expressions_vec.into_iter()) + .flat_map( + |(((advice, aux), permutation_expressions), lookup_expressions)| { + iter::empty() + // Custom constraints + .chain(meta.gates.iter().map(move |poly| { + poly.evaluate( + &|index| pk.fixed_cosets[index].clone(), + &|index| advice.advice_cosets[index].clone(), + &|index| aux.aux_cosets[index].clone(), + &|a, b| a + &b, + &|a, b| a * &b, + &|a, scalar| a * scalar, + ) + })) + // Permutation constraints, if any. + .chain(permutation_expressions.into_iter().flatten()) + // Lookup constraints, if any. + .chain(lookup_expressions.into_iter().flatten()) + }, + ) + .collect::>() + .into_iter(); // Construct the vanishing argument let vanishing = vanishing::Argument::construct(params, domain, expressions, y, transcript)?; let x = ChallengeX::get(transcript); - // Evaluate polynomials at omega^i x - let advice_evals: Vec<_> = meta - .advice_queries - .iter() - .map(|&(column, at)| { - eval_polynomial(&advice_polys[column.index()], domain.rotate_omega(*x, at)) - }) - .collect(); + // Compute and hash aux evals for each circuit instance + for aux in aux_vec.iter() { + // Evaluate polynomials at omega^i x + let aux_evals: Vec<_> = meta + .aux_queries + .iter() + .map(|&(column, at)| { + eval_polynomial(&aux.aux_polys[column.index()], domain.rotate_omega(*x, at)) + }) + .collect(); - let aux_evals: Vec<_> = meta - .aux_queries - .iter() - .map(|&(column, at)| { - eval_polynomial(&aux_polys[column.index()], domain.rotate_omega(*x, at)) - }) - .collect(); + // Hash each aux column evaluation + for eval in aux_evals.iter() { + transcript + .write_scalar(*eval) + .map_err(|_| Error::TranscriptError)?; + } + } + // Compute and hash advice evals for each circuit instance + for advice in advice_vec.iter() { + // Evaluate polynomials at omega^i x + let advice_evals: Vec<_> = meta + .advice_queries + .iter() + .map(|&(column, at)| { + eval_polynomial( + &advice.advice_polys[column.index()], + domain.rotate_omega(*x, at), + ) + }) + .collect(); + + // Hash each advice column evaluation + for eval in advice_evals.iter() { + transcript + .write_scalar(*eval) + .map_err(|_| Error::TranscriptError)?; + } + } + + // Compute and hash fixed evals (shared across all circuit instances) let fixed_evals: Vec<_> = meta .fixed_queries .iter() @@ -278,12 +421,8 @@ pub fn create_proof, ConcreteCircuit: Circ }) .collect(); - // Hash each column evaluation - for eval in advice_evals - .iter() - .chain(aux_evals.iter()) - .chain(fixed_evals.iter()) - { + // Hash each fixed column evaluation + for eval in fixed_evals.iter() { transcript .write_scalar(*eval) .map_err(|_| Error::TranscriptError)?; @@ -292,63 +431,98 @@ pub fn create_proof, ConcreteCircuit: Circ let vanishing = vanishing.evaluate(x, transcript)?; // Evaluate the permutations, if any, at omega^i x. - let permutations = permutations + let permutations_vec: Result>>, _> = permutations_vec .into_iter() - .zip(pk.permutations.iter()) - .map(|(p, pkey)| p.evaluate(pk, pkey, x, transcript)) - .collect::, _>>()?; + .map(|permutations| -> Result, _> { + permutations + .into_iter() + .zip(pk.permutations.iter()) + .map(|(p, pkey)| p.evaluate(pk, pkey, x, transcript)) + .collect::, _>>() + }) + .collect(); + + let permutations_vec = match permutations_vec { + Ok(permutations_vec) => permutations_vec, + Err(err) => return Err(err), + }; // Evaluate the lookups, if any, at omega^i x. - let lookups = lookups + let lookups_vec: Result>>, _> = lookups_vec .into_iter() - .map(|p| p.evaluate(pk, x, transcript)) - .collect::, _>>()?; + .map(|lookups| -> Result, _> { + lookups + .into_iter() + .map(|p| p.evaluate(pk, x, transcript)) + .collect::, _>>() + }) + .collect(); - let instances = iter::empty() - .chain( - pk.vk - .cs - .advice_queries - .iter() - .map(|&(column, at)| ProverQuery { - point: domain.rotate_omega(*x, at), - poly: &advice_polys[column.index()], - blind: advice_blinds[column.index()], - }), - ) - .chain( - pk.vk - .cs - .aux_queries - .iter() - .map(|&(column, at)| ProverQuery { - point: domain.rotate_omega(*x, at), - poly: &aux_polys[column.index()], - blind: Blind::default(), - }), - ) + let lookups_vec = match lookups_vec { + Ok(lookups_vec) => lookups_vec, + Err(err) => return Err(err), + }; + + let instances = aux_vec + .iter() + .zip(advice_vec.iter()) + .zip(permutations_vec.iter()) + .zip(lookups_vec.iter()) + .flat_map(|(((aux, advice), permutations), lookups)| { + iter::empty() + .chain( + pk.vk + .cs + .aux_queries + .iter() + .map(move |&(column, at)| ProverQuery { + point: domain.rotate_omega(*x, at), + poly: &aux.aux_polys[column.index()], + blind: Blind::default(), + }), + ) + .chain( + pk.vk + .cs + .advice_queries + .iter() + .map(move |&(column, at)| ProverQuery { + point: domain.rotate_omega(*x, at), + poly: &advice.advice_polys[column.index()], + blind: advice.advice_blinds[column.index()], + }), + ) + .chain( + permutations + .iter() + .zip(pk.permutations.iter()) + .map(move |(p, pkey)| p.open(pk, pkey, x)) + .into_iter() + .flatten(), + ) + .chain( + lookups + .iter() + .map(move |p| p.open(pk, x)) + .into_iter() + .flatten(), + ) + }) + .collect::>() + .into_iter() .chain( pk.vk .cs .fixed_queries .iter() - .map(|&(column, at)| ProverQuery { + .map(move |&(column, at)| ProverQuery { point: domain.rotate_omega(*x, at), poly: &pk.fixed_polys[column.index()], blind: Blind::default(), }), ) // We query the h(X) polynomial at x - .chain(vanishing.open(x)) - .chain( - permutations - .iter() - .zip(pk.permutations.iter()) - .map(|(p, pkey)| p.open(pk, pkey, x)) - .into_iter() - .flatten(), - ) - .chain(lookups.iter().map(|p| p.open(pk, x)).into_iter().flatten()); + .chain(vanishing.open(x)); multiopen::create_proof(params, transcript, instances).map_err(|_| Error::OpeningError) } From def65609b14556ba59a9243e681fa4872d2d5a65 Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Thu, 21 Jan 2021 08:04:44 +0800 Subject: [PATCH 2/5] Refactor PLONK verifier --- src/plonk/verifier.rs | 308 +++++++++++++++++++++++++----------------- 1 file changed, 184 insertions(+), 124 deletions(-) diff --git a/src/plonk/verifier.rs b/src/plonk/verifier.rs index 85c34c1..2b6548e 100644 --- a/src/plonk/verifier.rs +++ b/src/plonk/verifier.rs @@ -17,35 +17,49 @@ pub fn verify_proof<'a, C: CurveAffine, T: TranscriptRead>( params: &'a Params, vk: &VerifyingKey, msm: MSM<'a, C>, - aux_commitments: &[C], + aux_commitments_vec: &[&[C]], transcript: &mut T, ) -> Result, Error> { // Check that aux_commitments matches the expected number of aux columns - if aux_commitments.len() != vk.cs.num_aux_columns { - return Err(Error::IncompatibleParams); + for aux_commitments in aux_commitments_vec.iter() { + if aux_commitments.len() != vk.cs.num_aux_columns { + return Err(Error::IncompatibleParams); + } } - // Hash the aux (external) commitments into the transcript - for commitment in aux_commitments { - transcript - .common_point(*commitment) - .map_err(|_| Error::TranscriptError)? + let num_proofs = aux_commitments_vec.len(); + + for aux_commitments in aux_commitments_vec.iter() { + // Hash the aux (external) commitments into the transcript + for commitment in *aux_commitments { + transcript + .common_point(*commitment) + .map_err(|_| Error::TranscriptError)? + } } - // Hash the prover's advice commitments into the transcript - let advice_commitments = - read_n_points(transcript, vk.cs.num_advice_columns).map_err(|_| Error::TranscriptError)?; + let mut advice_commitments_vec = Vec::with_capacity(num_proofs); + for _ in 0..num_proofs { + // Hash the prover's advice commitments into the transcript + let advice_commitments = read_n_points(transcript, vk.cs.num_advice_columns) + .map_err(|_| Error::TranscriptError)?; + advice_commitments_vec.push(advice_commitments); + } // Sample theta challenge for keeping lookup columns linearly independent let theta = ChallengeTheta::get(transcript); - // Hash each lookup permuted commitment - let lookups = vk - .cs - .lookups - .iter() - .map(|argument| argument.read_permuted_commitments(transcript)) - .collect::, _>>()?; + let mut lookups_permuted_vec = Vec::with_capacity(num_proofs); + for _ in 0..num_proofs { + // Hash each lookup permuted commitment + let lookups = vk + .cs + .lookups + .iter() + .map(|argument| argument.read_permuted_commitments(transcript)) + .collect::, _>>()?; + lookups_permuted_vec.push(lookups); + } // Sample beta challenge let beta = ChallengeBeta::get(transcript); @@ -53,19 +67,27 @@ pub fn verify_proof<'a, C: CurveAffine, T: TranscriptRead>( // Sample gamma challenge let gamma = ChallengeGamma::get(transcript); - // Hash each permutation product commitment - let permutations = vk - .cs - .permutations - .iter() - .map(|argument| argument.read_product_commitment(transcript)) - .collect::, _>>()?; + let mut permutations_committed_vec = Vec::with_capacity(num_proofs); + for _ in 0..num_proofs { + // Hash each permutation product commitment + let permutations = vk + .cs + .permutations + .iter() + .map(|argument| argument.read_product_commitment(transcript)) + .collect::, _>>()?; + permutations_committed_vec.push(permutations); + } - // Hash each lookup product commitment - let lookups = lookups - .into_iter() - .map(|lookup| lookup.read_product_commitment(transcript)) - .collect::, _>>()?; + let mut lookups_committed_vec = Vec::with_capacity(num_proofs); + for lookups in lookups_permuted_vec.into_iter() { + // Hash each lookup product commitment + let lookups = lookups + .into_iter() + .map(|lookup| lookup.read_product_commitment(transcript)) + .collect::, _>>()?; + lookups_committed_vec.push(lookups); + } // Sample y challenge, which keeps the gates linearly independent. let y = ChallengeY::get(transcript); @@ -76,25 +98,43 @@ pub fn verify_proof<'a, C: CurveAffine, T: TranscriptRead>( // satisfied with high probability. let x = ChallengeX::get(transcript); - let advice_evals = read_n_scalars(transcript, vk.cs.advice_queries.len()) - .map_err(|_| Error::TranscriptError)?; - let aux_evals = - read_n_scalars(transcript, vk.cs.aux_queries.len()).map_err(|_| Error::TranscriptError)?; + let mut aux_evals_vec = Vec::with_capacity(num_proofs); + for _ in 0..num_proofs { + let aux_evals = read_n_scalars(transcript, vk.cs.aux_queries.len()) + .map_err(|_| Error::TranscriptError)?; + aux_evals_vec.push(aux_evals); + } + + let mut advice_evals_vec = Vec::with_capacity(num_proofs); + for _ in 0..num_proofs { + let advice_evals = read_n_scalars(transcript, vk.cs.advice_queries.len()) + .map_err(|_| Error::TranscriptError)?; + advice_evals_vec.push(advice_evals); + } + let fixed_evals = read_n_scalars(transcript, vk.cs.fixed_queries.len()) .map_err(|_| Error::TranscriptError)?; let vanishing = vanishing.evaluate(transcript)?; - let permutations = permutations - .into_iter() - .zip(vk.permutations.iter()) - .map(|(permutation, vkey)| permutation.evaluate(vkey, transcript)) - .collect::, _>>()?; + let mut permutations_evaluated_vec = Vec::with_capacity(num_proofs); + for permutations in permutations_committed_vec.into_iter() { + let permutations = permutations + .into_iter() + .zip(vk.permutations.iter()) + .map(|(permutation, vkey)| permutation.evaluate(vkey, transcript)) + .collect::, _>>()?; + permutations_evaluated_vec.push(permutations); + } - let lookups = lookups - .into_iter() - .map(|lookup| lookup.evaluate(transcript)) - .collect::, _>>()?; + let mut lookups_evaluated_vec = Vec::with_capacity(num_proofs); + for lookups in lookups_committed_vec.into_iter() { + let lookups = lookups + .into_iter() + .map(|lookup| lookup.evaluate(transcript)) + .collect::, _>>()?; + lookups_evaluated_vec.push(lookups); + } // This check ensures the circuit is satisfied so long as the polynomial // commitments open to the correct values. @@ -109,102 +149,122 @@ pub fn verify_proof<'a, C: CurveAffine, T: TranscriptRead>( * &vk.domain.get_barycentric_weight(); // l_0(x) // Compute the expected value of h(x) - let expressions = std::iter::empty() - // Evaluate the circuit using the custom gates provided - .chain(vk.cs.gates.iter().map(|poly| { - poly.evaluate( - &|index| fixed_evals[index], - &|index| advice_evals[index], - &|index| aux_evals[index], - &|a, b| a + &b, - &|a, b| a * &b, - &|a, scalar| a * &scalar, - ) - })) - .chain( - permutations - .iter() - .zip(vk.cs.permutations.iter()) - .map(|(p, argument)| { - p.expressions(vk, argument, &advice_evals, l_0, beta, gamma, x) - }) - .into_iter() - .flatten(), - ) - .chain( - lookups - .iter() - .zip(vk.cs.lookups.iter()) - .map(|(p, argument)| { - p.expressions( - vk, - l_0, - argument, - theta, - beta, - gamma, - &advice_evals, - &fixed_evals, - &aux_evals, + let expressions = advice_evals_vec + .iter() + .zip(aux_evals_vec.iter()) + .zip(permutations_evaluated_vec.iter()) + .zip(lookups_evaluated_vec.iter()) + .flat_map(|(((advice_evals, aux_evals), permutations), lookups)| { + let fixed_evals = fixed_evals.clone(); + let fixed_evals_copy = fixed_evals.clone(); + + std::iter::empty() + // Evaluate the circuit using the custom gates provided + .chain(vk.cs.gates.iter().map(move |poly| { + poly.evaluate( + &|index| fixed_evals[index], + &|index| advice_evals[index], + &|index| aux_evals[index], + &|a, b| a + &b, + &|a, b| a * &b, + &|a, scalar| a * &scalar, ) - }) - .into_iter() - .flatten(), - ); + })) + .chain( + permutations + .iter() + .zip(vk.cs.permutations.iter()) + .map(move |(p, argument)| { + p.expressions(vk, argument, &advice_evals, l_0, beta, gamma, x) + }) + .into_iter() + .flatten(), + ) + .chain( + lookups + .iter() + .zip(vk.cs.lookups.iter()) + .map(move |(p, argument)| { + p.expressions( + vk, + l_0, + argument, + theta, + beta, + gamma, + &advice_evals, + &fixed_evals_copy, + &aux_evals, + ) + }) + .into_iter() + .flatten(), + ) + }) + .collect::>() + .into_iter(); vanishing.verify(expressions, y, xn)?; } - let queries = iter::empty() - .chain( - vk.cs - .advice_queries - .iter() - .enumerate() - .map(|(query_index, &(column, at))| VerifierQuery { - point: vk.domain.rotate_omega(*x, at), - commitment: &advice_commitments[column.index()], - eval: advice_evals[query_index], - }), - ) - .chain( - vk.cs - .aux_queries - .iter() - .enumerate() - .map(|(query_index, &(column, at))| VerifierQuery { - point: vk.domain.rotate_omega(*x, at), - commitment: &aux_commitments[column.index()], - eval: aux_evals[query_index], - }), + let queries = aux_commitments_vec + .iter() + .zip(aux_evals_vec.iter()) + .zip(advice_commitments_vec.iter()) + .zip(advice_evals_vec.iter()) + .zip(permutations_evaluated_vec.iter()) + .zip(lookups_evaluated_vec.iter()) + .flat_map( + |( + ((((aux_commitments, aux_evals), advice_commitments), advice_evals), permutations), + lookups, + )| { + iter::empty() + .chain(vk.cs.aux_queries.iter().enumerate().map( + move |(query_index, &(column, at))| VerifierQuery { + point: vk.domain.rotate_omega(*x, at), + commitment: &aux_commitments[column.index()], + eval: aux_evals[query_index], + }, + )) + .chain(vk.cs.advice_queries.iter().enumerate().map( + move |(query_index, &(column, at))| VerifierQuery { + point: vk.domain.rotate_omega(*x, at), + commitment: &advice_commitments[column.index()], + eval: advice_evals[query_index], + }, + )) + .chain( + permutations + .iter() + .zip(vk.permutations.iter()) + .map(move |(p, vkey)| p.queries(vk, vkey, x)) + .into_iter() + .flatten(), + ) + .chain( + lookups + .iter() + .map(move |p| p.queries(vk, x)) + .into_iter() + .flatten(), + ) + }, ) + .collect::>() + .into_iter() .chain( vk.cs .fixed_queries .iter() .enumerate() - .map(|(query_index, &(column, at))| VerifierQuery { + .map(move |(query_index, &(column, at))| VerifierQuery { point: vk.domain.rotate_omega(*x, at), commitment: &vk.fixed_commitments[column.index()], - eval: fixed_evals[query_index], + eval: fixed_evals.clone()[query_index], }), ) - .chain(vanishing.queries(x)) - .chain( - permutations - .iter() - .zip(vk.permutations.iter()) - .map(|(p, vkey)| p.queries(vk, vkey, x)) - .into_iter() - .flatten(), - ) - .chain( - lookups - .iter() - .map(|p| p.queries(vk, x)) - .into_iter() - .flatten(), - ); + .chain(vanishing.queries(x)); // We are now convinced the circuit is satisfied so long as the // polynomial commitments open to the correct values. From de86391f0eeda1365548f9472551f3da6758b15a Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Wed, 20 Jan 2021 21:48:51 +0800 Subject: [PATCH 3/5] Update test to pass multiple ConcreteCircuits --- benches/plonk.rs | 6 ++++-- examples/performance_model.rs | 13 +++++++++++-- src/dev.rs | 2 ++ src/plonk.rs | 26 +++++++++++++++++++++----- 4 files changed, 38 insertions(+), 9 deletions(-) diff --git a/benches/plonk.rs b/benches/plonk.rs index 06f6317..cdc9e6c 100644 --- a/benches/plonk.rs +++ b/benches/plonk.rs @@ -20,6 +20,7 @@ fn bench_with_k(name: &str, k: u32, c: &mut Criterion) { // Initialize the polynomial commitment parameters let params: Params = Params::new(k); + #[derive(Copy, Clone)] struct PLONKConfig { a: Column, b: Column, @@ -43,6 +44,7 @@ fn bench_with_k(name: &str, k: u32, c: &mut Criterion) { fn copy(&mut self, a: Variable, b: Variable) -> Result<(), Error>; } + #[derive(Clone)] struct MyCircuit { a: Option, k: u32, @@ -241,7 +243,7 @@ fn bench_with_k(name: &str, k: u32, c: &mut Criterion) { // Create a proof let mut transcript = DummyHashWrite::init(vec![], Fq::one()); - create_proof(¶ms, &pk, &circuit, &[], &mut transcript) + create_proof(¶ms, &pk, &[circuit], &[], &mut transcript) .expect("proof generation should not fail") }); }); @@ -253,7 +255,7 @@ fn bench_with_k(name: &str, k: u32, c: &mut Criterion) { // Create a proof let mut transcript = DummyHashWrite::init(vec![], Fq::one()); - create_proof(¶ms, &pk, &circuit, &[], &mut transcript) + create_proof(¶ms, &pk, &[circuit], &[], &mut transcript) .expect("proof generation should not fail"); let proof = transcript.finalize(); diff --git a/examples/performance_model.rs b/examples/performance_model.rs index 15be99b..c19246b 100644 --- a/examples/performance_model.rs +++ b/examples/performance_model.rs @@ -16,6 +16,7 @@ use std::marker::PhantomData; #[derive(Copy, Clone, Debug)] pub struct Variable(Column, usize); +#[derive(Copy, Clone)] struct PLONKConfig { a: Column, b: Column, @@ -43,6 +44,7 @@ trait StandardCS { F: FnOnce() -> Result; } +#[derive(Clone)] struct MyCircuit { a: Option, k: u32, @@ -278,7 +280,7 @@ fn main() { // Create a proof let mut transcript = DummyHashWrite::init(vec![], Fq::one()); - create_proof(¶ms, &pk, &circuit, &[pubinputs], &mut transcript) + create_proof(¶ms, &pk, &[circuit], &[&[pubinputs]], &mut transcript) .expect("proof generation should not fail"); let proof: Vec = transcript.finalize(); @@ -288,7 +290,14 @@ fn main() { let pubinput_slice = &[pubinput]; let msm = params.empty_msm(); let mut transcript = DummyHashRead::init(&proof[..], Fq::one()); - let guard = verify_proof(¶ms, pk.get_vk(), msm, pubinput_slice, &mut transcript).unwrap(); + let guard = verify_proof( + ¶ms, + pk.get_vk(), + msm, + &[pubinput_slice], + &mut transcript, + ) + .unwrap(); let msm = guard.clone().use_challenges(); assert!(msm.eval()); diff --git a/src/dev.rs b/src/dev.rs index 9e63e7a..17b5b10 100644 --- a/src/dev.rs +++ b/src/dev.rs @@ -62,12 +62,14 @@ pub enum VerifyFailure { /// }; /// const K: u32 = 5; /// +/// #[derive(Copy, Clone)] /// struct MyConfig { /// a: Column, /// b: Column, /// c: Column, /// } /// +/// #[derive(Clone)] /// struct MyCircuit { /// a: Option, /// b: Option, diff --git a/src/plonk.rs b/src/plonk.rs index 284e9cf..239d362 100644 --- a/src/plonk.rs +++ b/src/plonk.rs @@ -164,6 +164,7 @@ fn test_proving() { // Initialize the polynomial commitment parameters let params: Params = Params::new(K); + #[derive(Copy, Clone)] struct PLONKConfig { a: Column, b: Column, @@ -197,6 +198,7 @@ fn test_proving() { fn lookup_table(&mut self, values: &[Vec]) -> Result<(), Error>; } + #[derive(Clone)] struct MyCircuit { a: Option, lookup_tables: Vec>, @@ -507,18 +509,25 @@ fn test_proving() { create_proof( ¶ms, &pk, - &circuit, - &[pubinputs.clone()], + &[circuit.clone(), circuit.clone()], + &[&[pubinputs.clone()], &[pubinputs.clone()]], &mut transcript, ) .expect("proof generation should not fail"); let proof: Vec = transcript.finalize(); let pubinput_slice = &[pubinput]; + let pubinput_slice_copy = &[pubinput]; let msm = params.empty_msm(); let mut transcript = DummyHashRead::init(&proof[..], Fq::one()); - let guard = - verify_proof(¶ms, pk.get_vk(), msm, pubinput_slice, &mut transcript).unwrap(); + let guard = verify_proof( + ¶ms, + pk.get_vk(), + msm, + &[pubinput_slice, pubinput_slice_copy], + &mut transcript, + ) + .unwrap(); { let msm = guard.clone().use_challenges(); assert!(msm.eval()); @@ -535,7 +544,14 @@ fn test_proving() { pk.get_vk().write(&mut vk_buffer).unwrap(); let vk = VerifyingKey::::read::<_, MyCircuit>(&mut &vk_buffer[..], ¶ms) .unwrap(); - let guard = verify_proof(¶ms, &vk, msm, pubinput_slice, &mut transcript).unwrap(); + let guard = verify_proof( + ¶ms, + &vk, + msm, + &[pubinput_slice, pubinput_slice_copy], + &mut transcript, + ) + .unwrap(); { let msm = guard.clone().use_challenges(); assert!(msm.eval()); From a00d7c2fa64278df466b7c3e29f2874e8eae659b Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Tue, 26 Jan 2021 15:23:29 +0800 Subject: [PATCH 4/5] Cleanups from code review Co-authored-by: Kris Nuttycombe Co-authored-by: Sean Bowe --- src/plonk/prover.rs | 177 ++++++++++++++++-------------------------- src/plonk/verifier.rs | 159 ++++++++++++++++++------------------- 2 files changed, 140 insertions(+), 196 deletions(-) diff --git a/src/plonk/prover.rs b/src/plonk/prover.rs index 0514147..31cb15e 100644 --- a/src/plonk/prover.rs +++ b/src/plonk/prover.rs @@ -34,13 +34,13 @@ pub fn create_proof, ConcreteCircuit: Circ let mut meta = ConstraintSystem::default(); let config = ConcreteCircuit::configure(&mut meta); - struct AuxSingle { - pub aux_values: Vec>, + struct AuxSingle<'a, C: CurveAffine> { + pub aux_values: &'a [Polynomial], pub aux_polys: Vec>, pub aux_cosets: Vec>, } - let aux_vec: Result, _> = auxs + let aux_vec: Vec> = auxs .iter() .map(|aux| -> Result, Error> { let aux_commitments_projective: Vec<_> = aux @@ -77,17 +77,12 @@ pub fn create_proof, ConcreteCircuit: Circ .collect(); Ok(AuxSingle { - aux_values: aux.to_vec(), + aux_values: *aux, aux_polys, aux_cosets, }) }) - .collect(); - - let aux_vec = match aux_vec { - Ok(aux_vec) => aux_vec, - Err(err) => return Err(err), - }; + .collect::, _>>()?; struct AdviceSingle { pub advice_values: Vec>, @@ -96,7 +91,7 @@ pub fn create_proof, ConcreteCircuit: Circ pub advice_blinds: Vec>, } - let advice_vec: Result, _> = circuits + let advice_vec: Vec> = circuits .iter() .map(|circuit| -> Result, Error> { struct WitnessCollection { @@ -202,50 +197,38 @@ pub fn create_proof, ConcreteCircuit: Circ advice_blinds, }) }) - .collect(); - - let advice_vec = match advice_vec { - Ok(advice_vec) => advice_vec, - Err(err) => return Err(err), - }; + .collect::, _>>()?; // Sample theta challenge for keeping lookup columns linearly independent let theta = ChallengeTheta::get(transcript); - let lookups_vec: Result>, _> = aux_vec + let lookups_vec: Vec>> = aux_vec .iter() .zip(advice_vec.iter()) - .map( - |(aux, advice)| -> Result>, Error> { - // Construct and commit to permuted values for each lookup - pk.vk - .cs - .lookups - .iter() - .map(|lookup| { - lookup.commit_permuted( - &pk, - ¶ms, - &domain, - theta, - &advice.advice_values, - &pk.fixed_values, - &aux.aux_values, - &advice.advice_cosets, - &pk.fixed_cosets, - &aux.aux_cosets, - transcript, - ) - }) - .collect() - }, - ) - .collect(); - - let lookups_vec = match lookups_vec { - Ok(lookups_vec) => lookups_vec, - Err(err) => return Err(err), - }; + .map(|(aux, advice)| -> Result, Error> { + // Construct and commit to permuted values for each lookup + pk.vk + .cs + .lookups + .iter() + .map(|lookup| { + lookup.commit_permuted( + &pk, + ¶ms, + &domain, + theta, + &advice.advice_values, + &pk.fixed_values, + &aux.aux_values, + &advice.advice_cosets, + &pk.fixed_cosets, + &aux.aux_cosets, + transcript, + ) + }) + .collect() + }) + .collect::, _>>()?; // Sample beta challenge let beta = ChallengeBeta::get(transcript); @@ -253,38 +236,31 @@ pub fn create_proof, ConcreteCircuit: Circ // Sample gamma challenge let gamma = ChallengeGamma::get(transcript); - let permutations_vec: Result>, _> = advice_vec + let permutations_vec: Vec>> = advice_vec .iter() - .map( - |advice| -> Result>, Error> { - // Commit to permutations, if any. - pk.vk - .cs - .permutations - .iter() - .zip(pk.permutations.iter()) - .map(|(p, pkey)| { - p.commit( - params, - pk, - pkey, - &advice.advice_values, - beta, - gamma, - transcript, - ) - }) - .collect() - }, - ) - .collect(); + .map(|advice| -> Result, Error> { + // Commit to permutations, if any. + pk.vk + .cs + .permutations + .iter() + .zip(pk.permutations.iter()) + .map(|(p, pkey)| { + p.commit( + params, + pk, + pkey, + &advice.advice_values, + beta, + gamma, + transcript, + ) + }) + .collect() + }) + .collect::, _>>()?; - let permutations_vec = match permutations_vec { - Ok(permutations_vec) => permutations_vec, - Err(err) => return Err(err), - }; - - let lookups_vec: Result>>, _> = lookups_vec + let lookups_vec: Vec>> = lookups_vec .into_iter() .map(|lookups| -> Result, _> { // Construct and commit to products for each lookup @@ -293,12 +269,7 @@ pub fn create_proof, ConcreteCircuit: Circ .map(|lookup| lookup.commit_product(&pk, ¶ms, theta, beta, gamma, transcript)) .collect::, _>>() }) - .collect(); - - let lookups_vec = match lookups_vec { - Ok(lookups_vec) => lookups_vec, - Err(err) => return Err(err), - }; + .collect::, _>>()?; // Obtain challenge for keeping all separate gates linearly independent let y = ChallengeY::get(transcript); @@ -308,6 +279,7 @@ pub fn create_proof, ConcreteCircuit: Circ .into_iter() .zip(advice_vec.iter()) .map(|(permutations, advice)| { + // Evaluate the h(X) polynomial's constraint system expressions for the permutation constraints, if any. let tmp: Vec<_> = permutations .into_iter() .zip(pk.vk.cs.permutations.iter()) @@ -362,9 +334,7 @@ pub fn create_proof, ConcreteCircuit: Circ // Lookup constraints, if any. .chain(lookup_expressions.into_iter().flatten()) }, - ) - .collect::>() - .into_iter(); + ); // Construct the vanishing argument let vanishing = vanishing::Argument::construct(params, domain, expressions, y, transcript)?; @@ -431,7 +401,7 @@ pub fn create_proof, ConcreteCircuit: Circ let vanishing = vanishing.evaluate(x, transcript)?; // Evaluate the permutations, if any, at omega^i x. - let permutations_vec: Result>>, _> = permutations_vec + let permutations_vec: Vec>> = permutations_vec .into_iter() .map(|permutations| -> Result, _> { permutations @@ -440,15 +410,10 @@ pub fn create_proof, ConcreteCircuit: Circ .map(|(p, pkey)| p.evaluate(pk, pkey, x, transcript)) .collect::, _>>() }) - .collect(); - - let permutations_vec = match permutations_vec { - Ok(permutations_vec) => permutations_vec, - Err(err) => return Err(err), - }; + .collect::, _>>()?; // Evaluate the lookups, if any, at omega^i x. - let lookups_vec: Result>>, _> = lookups_vec + let lookups_vec: Vec>> = lookups_vec .into_iter() .map(|lookups| -> Result, _> { lookups @@ -456,12 +421,7 @@ pub fn create_proof, ConcreteCircuit: Circ .map(|p| p.evaluate(pk, x, transcript)) .collect::, _>>() }) - .collect(); - - let lookups_vec = match lookups_vec { - Ok(lookups_vec) => lookups_vec, - Err(err) => return Err(err), - }; + .collect::, _>>()?; let instances = aux_vec .iter() @@ -496,17 +456,10 @@ pub fn create_proof, ConcreteCircuit: Circ permutations .iter() .zip(pk.permutations.iter()) - .map(move |(p, pkey)| p.open(pk, pkey, x)) - .into_iter() - .flatten(), - ) - .chain( - lookups - .iter() - .map(move |p| p.open(pk, x)) - .into_iter() - .flatten(), + .flat_map(move |(p, pkey)| p.open(pk, pkey, x)) + .into_iter(), ) + .chain(lookups.iter().flat_map(move |p| p.open(pk, x)).into_iter()) }) .collect::>() .into_iter() diff --git a/src/plonk/verifier.rs b/src/plonk/verifier.rs index 2b6548e..5f3abb6 100644 --- a/src/plonk/verifier.rs +++ b/src/plonk/verifier.rs @@ -38,28 +38,26 @@ pub fn verify_proof<'a, C: CurveAffine, T: TranscriptRead>( } } - let mut advice_commitments_vec = Vec::with_capacity(num_proofs); - for _ in 0..num_proofs { - // Hash the prover's advice commitments into the transcript - let advice_commitments = read_n_points(transcript, vk.cs.num_advice_columns) - .map_err(|_| Error::TranscriptError)?; - advice_commitments_vec.push(advice_commitments); - } + let advice_commitments_vec = (0..num_proofs) + .map(|_| -> Result, _> { + // Hash the prover's advice commitments into the transcript + read_n_points(transcript, vk.cs.num_advice_columns).map_err(|_| Error::TranscriptError) + }) + .collect::, _>>()?; // Sample theta challenge for keeping lookup columns linearly independent let theta = ChallengeTheta::get(transcript); - let mut lookups_permuted_vec = Vec::with_capacity(num_proofs); - for _ in 0..num_proofs { - // Hash each lookup permuted commitment - let lookups = vk - .cs - .lookups - .iter() - .map(|argument| argument.read_permuted_commitments(transcript)) - .collect::, _>>()?; - lookups_permuted_vec.push(lookups); - } + let lookups_permuted_vec = (0..num_proofs) + .map(|_| -> Result, _> { + // Hash each lookup permuted commitment + vk.cs + .lookups + .iter() + .map(|argument| argument.read_permuted_commitments(transcript)) + .collect::, _>>() + }) + .collect::, _>>()?; // Sample beta challenge let beta = ChallengeBeta::get(transcript); @@ -67,27 +65,27 @@ pub fn verify_proof<'a, C: CurveAffine, T: TranscriptRead>( // Sample gamma challenge let gamma = ChallengeGamma::get(transcript); - let mut permutations_committed_vec = Vec::with_capacity(num_proofs); - for _ in 0..num_proofs { - // Hash each permutation product commitment - let permutations = vk - .cs - .permutations - .iter() - .map(|argument| argument.read_product_commitment(transcript)) - .collect::, _>>()?; - permutations_committed_vec.push(permutations); - } + let permutations_committed_vec = (0..num_proofs) + .map(|_| -> Result, _> { + // Hash each permutation product commitment + vk.cs + .permutations + .iter() + .map(|argument| argument.read_product_commitment(transcript)) + .collect::, _>>() + }) + .collect::, _>>()?; - let mut lookups_committed_vec = Vec::with_capacity(num_proofs); - for lookups in lookups_permuted_vec.into_iter() { - // Hash each lookup product commitment - let lookups = lookups - .into_iter() - .map(|lookup| lookup.read_product_commitment(transcript)) - .collect::, _>>()?; - lookups_committed_vec.push(lookups); - } + let lookups_committed_vec = lookups_permuted_vec + .into_iter() + .map(|lookups| { + // Hash each lookup product commitment + lookups + .into_iter() + .map(|lookup| lookup.read_product_commitment(transcript)) + .collect::, _>>() + }) + .collect::, _>>()?; // Sample y challenge, which keeps the gates linearly independent. let y = ChallengeY::get(transcript); @@ -98,43 +96,44 @@ pub fn verify_proof<'a, C: CurveAffine, T: TranscriptRead>( // satisfied with high probability. let x = ChallengeX::get(transcript); - let mut aux_evals_vec = Vec::with_capacity(num_proofs); - for _ in 0..num_proofs { - let aux_evals = read_n_scalars(transcript, vk.cs.aux_queries.len()) - .map_err(|_| Error::TranscriptError)?; - aux_evals_vec.push(aux_evals); - } + let aux_evals_vec = (0..num_proofs) + .map(|_| -> Result, _> { + read_n_scalars(transcript, vk.cs.aux_queries.len()).map_err(|_| Error::TranscriptError) + }) + .collect::, _>>()?; - let mut advice_evals_vec = Vec::with_capacity(num_proofs); - for _ in 0..num_proofs { - let advice_evals = read_n_scalars(transcript, vk.cs.advice_queries.len()) - .map_err(|_| Error::TranscriptError)?; - advice_evals_vec.push(advice_evals); - } + let advice_evals_vec = (0..num_proofs) + .map(|_| -> Result, _> { + read_n_scalars(transcript, vk.cs.advice_queries.len()) + .map_err(|_| Error::TranscriptError) + }) + .collect::, _>>()?; let fixed_evals = read_n_scalars(transcript, vk.cs.fixed_queries.len()) .map_err(|_| Error::TranscriptError)?; let vanishing = vanishing.evaluate(transcript)?; - let mut permutations_evaluated_vec = Vec::with_capacity(num_proofs); - for permutations in permutations_committed_vec.into_iter() { - let permutations = permutations - .into_iter() - .zip(vk.permutations.iter()) - .map(|(permutation, vkey)| permutation.evaluate(vkey, transcript)) - .collect::, _>>()?; - permutations_evaluated_vec.push(permutations); - } + let permutations_evaluated_vec = permutations_committed_vec + .into_iter() + .map(|permutations| -> Result, _> { + permutations + .into_iter() + .zip(vk.permutations.iter()) + .map(|(permutation, vkey)| permutation.evaluate(vkey, transcript)) + .collect::, _>>() + }) + .collect::, _>>()?; - let mut lookups_evaluated_vec = Vec::with_capacity(num_proofs); - for lookups in lookups_committed_vec.into_iter() { - let lookups = lookups - .into_iter() - .map(|lookup| lookup.evaluate(transcript)) - .collect::, _>>()?; - lookups_evaluated_vec.push(lookups); - } + let lookups_evaluated_vec = lookups_committed_vec + .into_iter() + .map(|lookups| -> Result, _> { + lookups + .into_iter() + .map(|lookup| lookup.evaluate(transcript)) + .collect::, _>>() + }) + .collect::, _>>()?; // This check ensures the circuit is satisfied so long as the polynomial // commitments open to the correct values. @@ -174,17 +173,16 @@ pub fn verify_proof<'a, C: CurveAffine, T: TranscriptRead>( permutations .iter() .zip(vk.cs.permutations.iter()) - .map(move |(p, argument)| { + .flat_map(move |(p, argument)| { p.expressions(vk, argument, &advice_evals, l_0, beta, gamma, x) }) - .into_iter() - .flatten(), + .into_iter(), ) .chain( lookups .iter() .zip(vk.cs.lookups.iter()) - .map(move |(p, argument)| { + .flat_map(move |(p, argument)| { p.expressions( vk, l_0, @@ -197,12 +195,9 @@ pub fn verify_proof<'a, C: CurveAffine, T: TranscriptRead>( &aux_evals, ) }) - .into_iter() - .flatten(), + .into_iter(), ) - }) - .collect::>() - .into_iter(); + }); vanishing.verify(expressions, y, xn)?; } @@ -238,21 +233,17 @@ pub fn verify_proof<'a, C: CurveAffine, T: TranscriptRead>( permutations .iter() .zip(vk.permutations.iter()) - .map(move |(p, vkey)| p.queries(vk, vkey, x)) - .into_iter() - .flatten(), + .flat_map(move |(p, vkey)| p.queries(vk, vkey, x)) + .into_iter(), ) .chain( lookups .iter() - .map(move |p| p.queries(vk, x)) - .into_iter() - .flatten(), + .flat_map(move |p| p.queries(vk, x)) + .into_iter(), ) }, ) - .collect::>() - .into_iter() .chain( vk.cs .fixed_queries From ea14d99a83427ef38f43c81a0c90bf61f3c1aaa2 Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Sun, 31 Jan 2021 11:42:16 +0800 Subject: [PATCH 5/5] Renaming and cleanups from code review Co-authored-by: Sean Bowe --- src/plonk/prover.rs | 79 ++++++++++++++++++++----------------------- src/plonk/verifier.rs | 48 +++++++++++++------------- 2 files changed, 60 insertions(+), 67 deletions(-) diff --git a/src/plonk/prover.rs b/src/plonk/prover.rs index 31cb15e..4bc6ce2 100644 --- a/src/plonk/prover.rs +++ b/src/plonk/prover.rs @@ -40,7 +40,7 @@ pub fn create_proof, ConcreteCircuit: Circ pub aux_cosets: Vec>, } - let aux_vec: Vec> = auxs + let aux: Vec> = auxs .iter() .map(|aux| -> Result, Error> { let aux_commitments_projective: Vec<_> = aux @@ -91,7 +91,7 @@ pub fn create_proof, ConcreteCircuit: Circ pub advice_blinds: Vec>, } - let advice_vec: Vec> = circuits + let advice: Vec> = circuits .iter() .map(|circuit| -> Result, Error> { struct WitnessCollection { @@ -202,9 +202,9 @@ pub fn create_proof, ConcreteCircuit: Circ // Sample theta challenge for keeping lookup columns linearly independent let theta = ChallengeTheta::get(transcript); - let lookups_vec: Vec>> = aux_vec + let lookups: Vec>> = aux .iter() - .zip(advice_vec.iter()) + .zip(advice.iter()) .map(|(aux, advice)| -> Result, Error> { // Construct and commit to permuted values for each lookup pk.vk @@ -236,7 +236,7 @@ pub fn create_proof, ConcreteCircuit: Circ // Sample gamma challenge let gamma = ChallengeGamma::get(transcript); - let permutations_vec: Vec>> = advice_vec + let permutations: Vec>> = advice .iter() .map(|advice| -> Result, Error> { // Commit to permutations, if any. @@ -260,7 +260,7 @@ pub fn create_proof, ConcreteCircuit: Circ }) .collect::, _>>()?; - let lookups_vec: Vec>> = lookups_vec + let lookups: Vec>> = lookups .into_iter() .map(|lookups| -> Result, _> { // Construct and commit to products for each lookup @@ -274,28 +274,25 @@ pub fn create_proof, ConcreteCircuit: Circ // Obtain challenge for keeping all separate gates linearly independent let y = ChallengeY::get(transcript); - let (permutations_vec, permutation_expressions_vec): (Vec>, Vec>) = - permutations_vec - .into_iter() - .zip(advice_vec.iter()) - .map(|(permutations, advice)| { - // Evaluate the h(X) polynomial's constraint system expressions for the permutation constraints, if any. - let tmp: Vec<_> = permutations - .into_iter() - .zip(pk.vk.cs.permutations.iter()) - .zip(pk.permutations.iter()) - .map(|((p, argument), pkey)| { - p.construct(pk, argument, pkey, &advice.advice_cosets, beta, gamma) - }) - .collect(); + let (permutations, permutation_expressions): (Vec>, Vec>) = permutations + .into_iter() + .zip(advice.iter()) + .map(|(permutations, advice)| { + // Evaluate the h(X) polynomial's constraint system expressions for the permutation constraints, if any. + let tmp: Vec<_> = permutations + .into_iter() + .zip(pk.vk.cs.permutations.iter()) + .zip(pk.permutations.iter()) + .map(|((p, argument), pkey)| { + p.construct(pk, argument, pkey, &advice.advice_cosets, beta, gamma) + }) + .collect(); - tmp.into_iter().unzip() - }) - .collect::, Vec<_>)>>() - .into_iter() - .unzip(); + tmp.into_iter().unzip() + }) + .unzip(); - let (lookups_vec, lookup_expressions_vec): (Vec>, Vec>) = lookups_vec + let (lookups, lookup_expressions): (Vec>, Vec>) = lookups .into_iter() .map(|lookups| { // Evaluate the h(X) polynomial's constraint system expressions for the lookup constraints, if any. @@ -306,15 +303,13 @@ pub fn create_proof, ConcreteCircuit: Circ tmp.into_iter().unzip() }) - .collect::, Vec<_>)>>() - .into_iter() .unzip(); - let expressions = advice_vec + let expressions = advice .iter() - .zip(aux_vec.iter()) - .zip(permutation_expressions_vec.into_iter()) - .zip(lookup_expressions_vec.into_iter()) + .zip(aux.iter()) + .zip(permutation_expressions.into_iter()) + .zip(lookup_expressions.into_iter()) .flat_map( |(((advice, aux), permutation_expressions), lookup_expressions)| { iter::empty() @@ -342,7 +337,7 @@ pub fn create_proof, ConcreteCircuit: Circ let x = ChallengeX::get(transcript); // Compute and hash aux evals for each circuit instance - for aux in aux_vec.iter() { + for aux in aux.iter() { // Evaluate polynomials at omega^i x let aux_evals: Vec<_> = meta .aux_queries @@ -361,7 +356,7 @@ pub fn create_proof, ConcreteCircuit: Circ } // Compute and hash advice evals for each circuit instance - for advice in advice_vec.iter() { + for advice in advice.iter() { // Evaluate polynomials at omega^i x let advice_evals: Vec<_> = meta .advice_queries @@ -401,7 +396,7 @@ pub fn create_proof, ConcreteCircuit: Circ let vanishing = vanishing.evaluate(x, transcript)?; // Evaluate the permutations, if any, at omega^i x. - let permutations_vec: Vec>> = permutations_vec + let permutations: Vec>> = permutations .into_iter() .map(|permutations| -> Result, _> { permutations @@ -413,7 +408,7 @@ pub fn create_proof, ConcreteCircuit: Circ .collect::, _>>()?; // Evaluate the lookups, if any, at omega^i x. - let lookups_vec: Vec>> = lookups_vec + let lookups: Vec>> = lookups .into_iter() .map(|lookups| -> Result, _> { lookups @@ -423,11 +418,11 @@ pub fn create_proof, ConcreteCircuit: Circ }) .collect::, _>>()?; - let instances = aux_vec + let instances = aux .iter() - .zip(advice_vec.iter()) - .zip(permutations_vec.iter()) - .zip(lookups_vec.iter()) + .zip(advice.iter()) + .zip(permutations.iter()) + .zip(lookups.iter()) .flat_map(|(((aux, advice), permutations), lookups)| { iter::empty() .chain( @@ -461,14 +456,12 @@ pub fn create_proof, ConcreteCircuit: Circ ) .chain(lookups.iter().flat_map(move |p| p.open(pk, x)).into_iter()) }) - .collect::>() - .into_iter() .chain( pk.vk .cs .fixed_queries .iter() - .map(move |&(column, at)| ProverQuery { + .map(|&(column, at)| ProverQuery { point: domain.rotate_omega(*x, at), poly: &pk.fixed_polys[column.index()], blind: Blind::default(), diff --git a/src/plonk/verifier.rs b/src/plonk/verifier.rs index 5f3abb6..7525439 100644 --- a/src/plonk/verifier.rs +++ b/src/plonk/verifier.rs @@ -17,19 +17,19 @@ pub fn verify_proof<'a, C: CurveAffine, T: TranscriptRead>( params: &'a Params, vk: &VerifyingKey, msm: MSM<'a, C>, - aux_commitments_vec: &[&[C]], + aux_commitments: &[&[C]], transcript: &mut T, ) -> Result, Error> { // Check that aux_commitments matches the expected number of aux columns - for aux_commitments in aux_commitments_vec.iter() { + for aux_commitments in aux_commitments.iter() { if aux_commitments.len() != vk.cs.num_aux_columns { return Err(Error::IncompatibleParams); } } - let num_proofs = aux_commitments_vec.len(); + let num_proofs = aux_commitments.len(); - for aux_commitments in aux_commitments_vec.iter() { + for aux_commitments in aux_commitments.iter() { // Hash the aux (external) commitments into the transcript for commitment in *aux_commitments { transcript @@ -38,7 +38,7 @@ pub fn verify_proof<'a, C: CurveAffine, T: TranscriptRead>( } } - let advice_commitments_vec = (0..num_proofs) + let advice_commitments = (0..num_proofs) .map(|_| -> Result, _> { // Hash the prover's advice commitments into the transcript read_n_points(transcript, vk.cs.num_advice_columns).map_err(|_| Error::TranscriptError) @@ -48,7 +48,7 @@ pub fn verify_proof<'a, C: CurveAffine, T: TranscriptRead>( // Sample theta challenge for keeping lookup columns linearly independent let theta = ChallengeTheta::get(transcript); - let lookups_permuted_vec = (0..num_proofs) + let lookups_permuted = (0..num_proofs) .map(|_| -> Result, _> { // Hash each lookup permuted commitment vk.cs @@ -65,7 +65,7 @@ pub fn verify_proof<'a, C: CurveAffine, T: TranscriptRead>( // Sample gamma challenge let gamma = ChallengeGamma::get(transcript); - let permutations_committed_vec = (0..num_proofs) + let permutations_committed = (0..num_proofs) .map(|_| -> Result, _> { // Hash each permutation product commitment vk.cs @@ -76,7 +76,7 @@ pub fn verify_proof<'a, C: CurveAffine, T: TranscriptRead>( }) .collect::, _>>()?; - let lookups_committed_vec = lookups_permuted_vec + let lookups_committed = lookups_permuted .into_iter() .map(|lookups| { // Hash each lookup product commitment @@ -96,13 +96,13 @@ pub fn verify_proof<'a, C: CurveAffine, T: TranscriptRead>( // satisfied with high probability. let x = ChallengeX::get(transcript); - let aux_evals_vec = (0..num_proofs) + let aux_evals = (0..num_proofs) .map(|_| -> Result, _> { read_n_scalars(transcript, vk.cs.aux_queries.len()).map_err(|_| Error::TranscriptError) }) .collect::, _>>()?; - let advice_evals_vec = (0..num_proofs) + let advice_evals = (0..num_proofs) .map(|_| -> Result, _> { read_n_scalars(transcript, vk.cs.advice_queries.len()) .map_err(|_| Error::TranscriptError) @@ -114,7 +114,7 @@ pub fn verify_proof<'a, C: CurveAffine, T: TranscriptRead>( let vanishing = vanishing.evaluate(transcript)?; - let permutations_evaluated_vec = permutations_committed_vec + let permutations_evaluated = permutations_committed .into_iter() .map(|permutations| -> Result, _> { permutations @@ -125,7 +125,7 @@ pub fn verify_proof<'a, C: CurveAffine, T: TranscriptRead>( }) .collect::, _>>()?; - let lookups_evaluated_vec = lookups_committed_vec + let lookups_evaluated = lookups_committed .into_iter() .map(|lookups| -> Result, _> { lookups @@ -148,11 +148,11 @@ pub fn verify_proof<'a, C: CurveAffine, T: TranscriptRead>( * &vk.domain.get_barycentric_weight(); // l_0(x) // Compute the expected value of h(x) - let expressions = advice_evals_vec + let expressions = advice_evals .iter() - .zip(aux_evals_vec.iter()) - .zip(permutations_evaluated_vec.iter()) - .zip(lookups_evaluated_vec.iter()) + .zip(aux_evals.iter()) + .zip(permutations_evaluated.iter()) + .zip(lookups_evaluated.iter()) .flat_map(|(((advice_evals, aux_evals), permutations), lookups)| { let fixed_evals = fixed_evals.clone(); let fixed_evals_copy = fixed_evals.clone(); @@ -202,13 +202,13 @@ pub fn verify_proof<'a, C: CurveAffine, T: TranscriptRead>( vanishing.verify(expressions, y, xn)?; } - let queries = aux_commitments_vec + let queries = aux_commitments .iter() - .zip(aux_evals_vec.iter()) - .zip(advice_commitments_vec.iter()) - .zip(advice_evals_vec.iter()) - .zip(permutations_evaluated_vec.iter()) - .zip(lookups_evaluated_vec.iter()) + .zip(aux_evals.iter()) + .zip(advice_commitments.iter()) + .zip(advice_evals.iter()) + .zip(permutations_evaluated.iter()) + .zip(lookups_evaluated.iter()) .flat_map( |( ((((aux_commitments, aux_evals), advice_commitments), advice_evals), permutations), @@ -249,10 +249,10 @@ pub fn verify_proof<'a, C: CurveAffine, T: TranscriptRead>( .fixed_queries .iter() .enumerate() - .map(move |(query_index, &(column, at))| VerifierQuery { + .map(|(query_index, &(column, at))| VerifierQuery { point: vk.domain.rotate_omega(*x, at), commitment: &vk.fixed_commitments[column.index()], - eval: fixed_evals.clone()[query_index], + eval: fixed_evals[query_index], }), ) .chain(vanishing.queries(x));