From fd91b6b42cfa6df603b4946411b8772056c9f81f Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Fri, 26 Feb 2021 18:48:02 -0700 Subject: [PATCH] Allow MSMs to be queried and not just raw commitments. This allows us to avoid some interstitial arithmetic in the vanishing argument. --- src/plonk/lookup/verifier.rs | 58 ++++++++++----------- src/plonk/permutation/verifier.rs | 36 ++++++------- src/plonk/vanishing/verifier.rs | 53 ++++++++++--------- src/plonk/verifier.rs | 40 ++++++++------ src/poly/multiopen.rs | 86 +++++++++++++++++++------------ src/poly/multiopen/verifier.rs | 47 ++++++++--------- 6 files changed, 173 insertions(+), 147 deletions(-) diff --git a/src/plonk/lookup/verifier.rs b/src/plonk/lookup/verifier.rs index 10c9f8d0..a2871f49 100644 --- a/src/plonk/lookup/verifier.rs +++ b/src/plonk/lookup/verifier.rs @@ -168,43 +168,43 @@ impl Evaluated { )) } - pub(in crate::plonk) fn queries<'a>( - &'a self, - vk: &'a VerifyingKey, + pub(in crate::plonk) fn queries<'r, 'params: 'r>( + &'r self, + vk: &'r VerifyingKey, x: ChallengeX, - ) -> impl Iterator> + Clone { + ) -> impl Iterator> + Clone { let x_inv = vk.domain.rotate_omega(*x, Rotation(-1)); iter::empty() // Open lookup product commitments at x - .chain(Some(VerifierQuery { - point: *x, - commitment: &self.committed.product_commitment, - eval: self.product_eval, - })) + .chain(Some(VerifierQuery::new_commitment( + &self.committed.product_commitment, + *x, + self.product_eval, + ))) // Open lookup input commitments at x - .chain(Some(VerifierQuery { - point: *x, - commitment: &self.committed.permuted.permuted_input_commitment, - eval: self.permuted_input_eval, - })) + .chain(Some(VerifierQuery::new_commitment( + &self.committed.permuted.permuted_input_commitment, + *x, + self.permuted_input_eval, + ))) // Open lookup table commitments at x - .chain(Some(VerifierQuery { - point: *x, - commitment: &self.committed.permuted.permuted_table_commitment, - eval: self.permuted_table_eval, - })) + .chain(Some(VerifierQuery::new_commitment( + &self.committed.permuted.permuted_table_commitment, + *x, + self.permuted_table_eval, + ))) // Open lookup input commitments at \omega^{-1} x - .chain(Some(VerifierQuery { - point: x_inv, - commitment: &self.committed.permuted.permuted_input_commitment, - eval: self.permuted_input_inv_eval, - })) + .chain(Some(VerifierQuery::new_commitment( + &self.committed.permuted.permuted_input_commitment, + x_inv, + self.permuted_input_inv_eval, + ))) // Open lookup product commitments at \omega^{-1} x - .chain(Some(VerifierQuery { - point: x_inv, - commitment: &self.committed.product_commitment, - eval: self.product_inv_eval, - })) + .chain(Some(VerifierQuery::new_commitment( + &self.committed.product_commitment, + x_inv, + self.product_inv_eval, + ))) } } diff --git a/src/plonk/permutation/verifier.rs b/src/plonk/permutation/verifier.rs index c19a7b7a..3c4bae21 100644 --- a/src/plonk/permutation/verifier.rs +++ b/src/plonk/permutation/verifier.rs @@ -128,35 +128,33 @@ impl Evaluated { })) } - pub(in crate::plonk) fn queries<'a>( - &'a self, - vk: &'a plonk::VerifyingKey, - vkey: &'a VerifyingKey, + pub(in crate::plonk) fn queries<'r, 'params: 'r>( + &'r self, + vk: &'r plonk::VerifyingKey, + vkey: &'r VerifyingKey, x: ChallengeX, - ) -> impl Iterator> + Clone { + ) -> impl Iterator> + Clone { let x_inv = vk.domain.rotate_omega(*x, Rotation(-1)); iter::empty() // Open permutation product commitments at x and \omega^{-1} x - .chain(Some(VerifierQuery { - point: *x, - commitment: &self.permutation_product_commitment, - eval: self.permutation_product_eval, - })) - .chain(Some(VerifierQuery { - point: x_inv, - commitment: &self.permutation_product_commitment, - eval: self.permutation_product_inv_eval, - })) + .chain(Some(VerifierQuery::new_commitment( + &self.permutation_product_commitment, + *x, + self.permutation_product_eval, + ))) + .chain(Some(VerifierQuery::new_commitment( + &self.permutation_product_commitment, + x_inv, + self.permutation_product_inv_eval, + ))) // Open permutation commitments for each permutation argument at x .chain( vkey.commitments .iter() .zip(self.permutation_evals.iter()) - .map(move |(commitment, &eval)| VerifierQuery { - point: *x, - commitment, - eval, + .map(move |(commitment, &eval)| { + VerifierQuery::new_commitment(commitment, *x, eval) }), ) } diff --git a/src/plonk/vanishing/verifier.rs b/src/plonk/vanishing/verifier.rs index 997bac99..4ef86584 100644 --- a/src/plonk/vanishing/verifier.rs +++ b/src/plonk/vanishing/verifier.rs @@ -1,10 +1,12 @@ use ff::Field; -use group::{Curve, Group}; use crate::{ arithmetic::CurveAffine, plonk::{Error, VerifyingKey}, - poly::multiopen::VerifierQuery, + poly::{ + commitment::{Params, MSM}, + multiopen::VerifierQuery, + }, transcript::{read_n_points, EncodedChallenge, TranscriptRead}, }; @@ -15,8 +17,8 @@ pub struct Committed { h_commitments: Vec, } -pub struct Evaluated { - h_commitment: C, +pub struct Evaluated<'params, C: CurveAffine> { + h_commitment: MSM<'params, C>, expected_h_eval: C::Scalar, } @@ -34,23 +36,25 @@ impl Argument { } impl Committed { - pub(in crate::plonk) fn verify( + pub(in crate::plonk) fn verify<'params>( self, + params: &'params Params, expressions: impl Iterator, y: ChallengeY, xn: C::Scalar, - ) -> Result, Error> { + ) -> Result, Error> { let expected_h_eval = expressions.fold(C::Scalar::zero(), |h_eval, v| h_eval * &*y + &v); let expected_h_eval = expected_h_eval * ((xn - C::Scalar::one()).invert().unwrap()); - let h_commitment = self - .h_commitments - .iter() - .rev() - .fold(C::CurveExt::identity(), |acc, eval| { - acc * xn + eval.to_curve() - }) - .to_affine(); + let h_commitment = + self.h_commitments + .iter() + .rev() + .fold(params.empty_msm(), |mut acc, commitment| { + acc.scale(xn); + acc.append_term(C::Scalar::one(), *commitment); + acc + }); Ok(Evaluated { expected_h_eval, @@ -59,16 +63,19 @@ impl Committed { } } -impl Evaluated { - pub(in crate::plonk) fn queries( - &self, +impl<'params, C: CurveAffine> Evaluated<'params, C> { + pub(in crate::plonk) fn queries<'r>( + &'r self, x: ChallengeX, - ) -> impl Iterator> + Clone { - Some(VerifierQuery { - point: *x, - commitment: &self.h_commitment, - eval: self.expected_h_eval, - }) + ) -> impl Iterator> + Clone + where + 'params: 'r, + { + Some(VerifierQuery::new_msm( + &self.h_commitment, + *x, + self.expected_h_eval, + )) .into_iter() } } diff --git a/src/plonk/verifier.rs b/src/plonk/verifier.rs index 3d95a6e3..75a53aea 100644 --- a/src/plonk/verifier.rs +++ b/src/plonk/verifier.rs @@ -13,13 +13,13 @@ use crate::poly::{ use crate::transcript::{read_n_points, read_n_scalars, EncodedChallenge, TranscriptRead}; /// Returns a boolean indicating whether or not the proof is valid -pub fn verify_proof<'a, C: CurveAffine, E: EncodedChallenge, T: TranscriptRead>( - params: &'a Params, +pub fn verify_proof<'params, C: CurveAffine, E: EncodedChallenge, T: TranscriptRead>( + params: &'params Params, vk: &VerifyingKey, - msm: MSM<'a, C>, + msm: MSM<'params, C>, instance_commitments: &[&[C]], transcript: &mut T, -) -> Result, Error> { +) -> Result, Error> { // Check that instance_commitments matches the expected number of instance columns for instance_commitments in instance_commitments.iter() { if instance_commitments.len() != vk.cs.num_instance_columns { @@ -217,7 +217,7 @@ pub fn verify_proof<'a, C: CurveAffine, E: EncodedChallenge, T: TranscriptRea }, ); - vanishing.verify(expressions, y, xn)? + vanishing.verify(params, expressions, y, xn)? }; let queries = instance_commitments @@ -237,17 +237,21 @@ pub fn verify_proof<'a, C: CurveAffine, E: EncodedChallenge, T: TranscriptRea )| { iter::empty() .chain(vk.cs.instance_queries.iter().enumerate().map( - move |(query_index, &(column, at))| VerifierQuery { - point: vk.domain.rotate_omega(*x, at), - commitment: &instance_commitments[column.index()], - eval: instance_evals[query_index], + move |(query_index, &(column, at))| { + VerifierQuery::new_commitment( + &instance_commitments[column.index()], + vk.domain.rotate_omega(*x, at), + instance_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], + move |(query_index, &(column, at))| { + VerifierQuery::new_commitment( + &advice_commitments[column.index()], + vk.domain.rotate_omega(*x, at), + advice_evals[query_index], + ) }, )) .chain( @@ -270,10 +274,12 @@ pub fn verify_proof<'a, C: CurveAffine, E: EncodedChallenge, T: TranscriptRea .fixed_queries .iter() .enumerate() - .map(|(query_index, &(column, at))| VerifierQuery { - point: vk.domain.rotate_omega(*x, at), - commitment: &vk.fixed_commitments[column.index()], - eval: fixed_evals[query_index], + .map(|(query_index, &(column, at))| { + VerifierQuery::new_commitment( + &vk.fixed_commitments[column.index()], + vk.domain.rotate_omega(*x, at), + fixed_evals[query_index], + ) }), ) .chain(vanishing.queries(x)); diff --git a/src/poly/multiopen.rs b/src/poly/multiopen.rs index eed97b80..ac91bf44 100644 --- a/src/poly/multiopen.rs +++ b/src/poly/multiopen.rs @@ -51,13 +51,55 @@ pub struct ProverQuery<'a, C: CurveAffine> { /// A polynomial query at a point #[derive(Debug, Clone)] -pub struct VerifierQuery<'a, C: CurveAffine> { +pub struct VerifierQuery<'r, 'params: 'r, C: CurveAffine> { /// point at which polynomial is queried - pub point: C::Scalar, + point: C::Scalar, /// commitment to polynomial - pub commitment: &'a C, + commitment: CommitmentReference<'r, 'params, C>, /// evaluation of polynomial at query point - pub eval: C::Scalar, + eval: C::Scalar, +} + +impl<'r, 'params: 'r, C: CurveAffine> VerifierQuery<'r, 'params, C> { + /// Create a new verifier query based on a commitment + pub fn new_commitment(commitment: &'r C, point: C::Scalar, eval: C::Scalar) -> Self { + VerifierQuery { + point, + eval, + commitment: CommitmentReference::Commitment(commitment), + } + } + + /// Create a new verifier query based on a linear combination of commitments + pub fn new_msm( + msm: &'r commitment::MSM<'params, C>, + point: C::Scalar, + eval: C::Scalar, + ) -> Self { + VerifierQuery { + point, + eval, + commitment: CommitmentReference::MSM(msm), + } + } +} + +#[derive(Copy, Clone, Debug)] +enum CommitmentReference<'r, 'params: 'r, C: CurveAffine> { + Commitment(&'r C), + MSM(&'r commitment::MSM<'params, C>), +} + +impl<'r, 'params: 'r, C: CurveAffine> PartialEq for CommitmentReference<'r, 'params, C> { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (&CommitmentReference::Commitment(a), &CommitmentReference::Commitment(b)) => { + std::ptr::eq(a, b) + } + (&CommitmentReference::MSM(a), &CommitmentReference::MSM(b)) => std::ptr::eq(a, b), + _ => false, + } + } } struct CommitmentData { @@ -279,21 +321,9 @@ fn test_roundtrip() { ¶ms, &mut transcript, std::iter::empty() - .chain(Some(VerifierQuery { - point: x, - commitment: &a, - eval: avx, - })) - .chain(Some(VerifierQuery { - point: x, - commitment: &b, - eval: avx, // NB: wrong! - })) - .chain(Some(VerifierQuery { - point: y, - commitment: &c, - eval: cvy, - })), + .chain(Some(VerifierQuery::new_commitment(&a, x, avx))) + .chain(Some(VerifierQuery::new_commitment(&b, x, avx))) // NB: wrong! + .chain(Some(VerifierQuery::new_commitment(&c, y, cvy))), msm, ) .unwrap(); @@ -313,21 +343,9 @@ fn test_roundtrip() { ¶ms, &mut transcript, std::iter::empty() - .chain(Some(VerifierQuery { - point: x, - commitment: &a, - eval: avx, - })) - .chain(Some(VerifierQuery { - point: x, - commitment: &b, - eval: bvx, - })) - .chain(Some(VerifierQuery { - point: y, - commitment: &c, - eval: cvy, - })), + .chain(Some(VerifierQuery::new_commitment(&a, x, avx))) + .chain(Some(VerifierQuery::new_commitment(&b, x, bvx))) + .chain(Some(VerifierQuery::new_commitment(&c, y, cvy))), msm, ) .unwrap(); diff --git a/src/poly/multiopen/verifier.rs b/src/poly/multiopen/verifier.rs index b02f5c2d..5fca01fc 100644 --- a/src/poly/multiopen/verifier.rs +++ b/src/poly/multiopen/verifier.rs @@ -5,8 +5,8 @@ use super::super::{ Error, }; use super::{ - construct_intermediate_sets, ChallengeX1, ChallengeX2, ChallengeX3, ChallengeX4, Query, - VerifierQuery, + construct_intermediate_sets, ChallengeX1, ChallengeX2, ChallengeX3, ChallengeX4, + CommitmentReference, Query, VerifierQuery, }; use crate::arithmetic::{eval_polynomial, lagrange_interpolate, CurveAffine, FieldExt}; use crate::transcript::{EncodedChallenge, TranscriptRead}; @@ -19,20 +19,20 @@ struct CommitmentData { /// Verify a multi-opening proof pub fn verify_proof< - 'b, - 'a: 'b, + 'r, + 'params: 'r, I, C: CurveAffine, E: EncodedChallenge, T: TranscriptRead, >( - params: &'a Params, + params: &'params Params, transcript: &mut T, queries: I, - mut msm: MSM<'a, C>, -) -> Result, Error> + mut msm: MSM<'params, C>, +) -> Result, Error> where - I: IntoIterator> + Clone, + I: IntoIterator> + Clone, { // Scale the MSM by a random factor to ensure that if the existing MSM // has is_zero() == false then this argument won't be able to interfere @@ -61,7 +61,14 @@ where { let mut accumulate = |set_idx: usize, new_commitment, evals: Vec| { q_commitments[set_idx].scale(*x_1); - q_commitments[set_idx].append_term(C::Scalar::one(), new_commitment); + match new_commitment { + CommitmentReference::Commitment(c) => { + q_commitments[set_idx].append_term(C::Scalar::one(), *c); + } + CommitmentReference::MSM(msm) => { + q_commitments[set_idx].add_msm(msm); + } + } for (eval, set_eval) in evals.iter().zip(q_eval_sets[set_idx].iter_mut()) { *set_eval *= &(*x_1); *set_eval += eval; @@ -72,9 +79,9 @@ where // For each set, we collapse each commitment's evals pointwise. for commitment_data in commitment_map.into_iter() { accumulate( - commitment_data.set_index, // set_idx, - *commitment_data.commitment.0, // commitment, - commitment_data.evals, // evals + commitment_data.set_index, // set_idx, + commitment_data.commitment, // commitment, + commitment_data.evals, // evals ); } } @@ -128,18 +135,8 @@ where super::commitment::verify_proof(params, msm, transcript, *x_3, msm_eval) } -#[doc(hidden)] -#[derive(Copy, Clone)] -pub struct CommitmentPointer<'a, C>(&'a C); - -impl<'a, C> PartialEq for CommitmentPointer<'a, C> { - fn eq(&self, other: &Self) -> bool { - std::ptr::eq(self.0, other.0) - } -} - -impl<'a, C: CurveAffine> Query for VerifierQuery<'a, C> { - type Commitment = CommitmentPointer<'a, C>; +impl<'a, 'b, C: CurveAffine> Query for VerifierQuery<'a, 'b, C> { + type Commitment = CommitmentReference<'a, 'b, C>; type Eval = C::Scalar; fn get_point(&self) -> C::Scalar { @@ -149,6 +146,6 @@ impl<'a, C: CurveAffine> Query for VerifierQuery<'a, C> { self.eval } fn get_commitment(&self) -> Self::Commitment { - CommitmentPointer(self.commitment) + self.commitment } }