From d41fcf842ba665aadbb765c82d2dd96a965eb65f Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Fri, 11 Sep 2020 13:42:11 +0800 Subject: [PATCH] Modify MSM and Guard structs and methods --- src/arithmetic.rs | 4 - src/plonk/verifier.rs | 9 +- src/poly/commitment.rs | 201 ++++++++++++++++---------------- src/poly/commitment/verifier.rs | 43 ++++--- 4 files changed, 128 insertions(+), 129 deletions(-) diff --git a/src/arithmetic.rs b/src/arithmetic.rs index e74cfee..312cfe5 100644 --- a/src/arithmetic.rs +++ b/src/arithmetic.rs @@ -70,10 +70,6 @@ where } /// This is a 128-bit verifier challenge. -/// -/// The verifier samples its challenge here as u^2, i.e. the square of the -/// actual challenge. This is an optimisation that is documented in Section 6.3 -/// of the [Halo](https://eprint.iacr.org/2019/1021) paper. #[derive(Copy, Clone, Debug)] pub struct Challenge(pub(crate) u128); diff --git a/src/plonk/verifier.rs b/src/plonk/verifier.rs index 6250397..1b303aa 100644 --- a/src/plonk/verifier.rs +++ b/src/plonk/verifier.rs @@ -264,11 +264,12 @@ impl Proof { } // Verify the opening proof - let (challenges, mut guard) = self + let default_msm = MSM::default(¶ms); + let (challenges, guard) = self .opening .verify( params, - &mut MSM::default(¶ms), + default_msm, &mut transcript, x_6, &f_commitment.to_affine(), @@ -276,8 +277,8 @@ impl Proof { ) .unwrap(); - let msm: MSM = guard.use_challenges(challenges).unwrap(); + let msm: &MSM = &guard.use_challenges(params, challenges).unwrap(); - msm.is_zero() + msm.is_zero(params) } } diff --git a/src/poly/commitment.rs b/src/poly/commitment.rs index 8fd2ebc..45fd0d8 100644 --- a/src/poly/commitment.rs +++ b/src/poly/commitment.rs @@ -27,60 +27,89 @@ pub struct OpeningProof { /// A multiscalar multiplication in the polynomial commitment scheme #[derive(Debug)] pub struct MSM { - /// Vector of random generators - pub g: Vec, + /// TODO: documentation + pub g_scalars: Option>, - /// Random generator - pub h: C, + /// TODO: documentation + pub h_scalar: Option, - /// Scalars in the multiscalar multiplication - pub scalars: Vec, + /// TODO: documentation + pub other_scalars: Vec, - /// Points in the multiscalar multiplication - pub bases: Vec, + /// TODO: documentation + pub other_bases: Vec, } impl<'a, C: CurveAffine> MSM { /// Empty MSM - pub fn default(params: &'a Params) -> Self { - let scalars: Vec = - Vec::with_capacity(params.k as usize * 2 + 4 + params.n as usize); - let bases: Vec = Vec::with_capacity(params.k as usize * 2 + 4 + params.n as usize); + pub fn default(params: &Params) -> Self { + let g_scalars = Some(vec![C::Scalar::one(); params.n as usize]); + let h_scalar = Some(C::Scalar::one()); + let other_scalars: Vec = Vec::with_capacity(params.k as usize * 2 + 3); + let other_bases: Vec = Vec::with_capacity(params.k as usize * 2 + 3); MSM { - g: params.g.clone(), - h: params.h.clone(), - scalars, - bases, + g_scalars, + h_scalar, + other_scalars, + other_bases, } } /// Add arbitrary term (the scalar and the point) pub fn add_term(&mut self, scalar: C::Scalar, point: C) { - &self.scalars.push(scalar); - &self.bases.push(point); + &self.other_scalars.push(scalar); + &self.other_bases.push(point); } - /// Add term to g - pub fn add_to_g(&mut self, point: C) { - &self.g.push(point); - } - - /// Add term to h - pub fn add_to_h(&mut self, point: C) { - self.h = self.h.add(point).to_affine(); - } - - /// Scale by a random blinding factor - pub fn scale(&mut self, factor: C::Scalar) { - for scalar in self.scalars.iter_mut() { - *scalar *= &factor; + /// Add a vector of scalars to `g_scalars` + pub fn add_to_g(&mut self, scalars: Vec) { + for (g_scalar, scalar) in self + .g_scalars + .as_mut() + .unwrap() + .iter_mut() + .zip(scalars.iter()) + { + *g_scalar += &scalar; } } + /// Add term to h + pub fn add_to_h(&mut self, scalar: C::Scalar) { + self.h_scalar = Some(self.h_scalar.unwrap() + &scalar); + } + + /// Scale all scalars in the MSM by a random blinding factor + pub fn scale(&mut self, factor: C::Scalar) { + for g_scalar in self.g_scalars.as_mut().unwrap().iter_mut() { + *g_scalar *= &factor; + } + for other_scalar in self.other_scalars.iter_mut() { + *other_scalar *= &factor; + } + self.h_scalar = Some(self.h_scalar.unwrap() * &factor); + } + /// Perform multiexp and check that it results in zero - pub fn is_zero(&self) -> bool { - bool::from(best_multiexp(&self.scalars, &self.bases).is_zero()) + pub fn is_zero(&self, params: &'a Params) -> bool { + let mut scalars: Vec = vec![]; + let mut bases: Vec = vec![]; + + scalars.extend(&self.other_scalars); + bases.extend(&self.other_bases); + + if let Some(h_scalar) = self.h_scalar { + scalars.push(h_scalar); + bases.push(params.h); + } + + if let Some(g_scalars) = &self.g_scalars { + scalars.extend(g_scalars); + bases.extend(params.g.iter()); + } + + bool::from(best_multiexp(&scalars, &bases).is_zero()) } } @@ -219,90 +248,70 @@ impl Params { /// A guard returned by the verifier #[derive(Debug)] -pub struct Guard<'a, C: CurveAffine> { - /// Vector of random generators - pub g: Vec, - - /// Random generator - pub h: C, +pub struct Guard { + /// MSM + msm: MSM, /// Negation of z1 value in the OpeningProof - pub neg_z1: C::Scalar, + neg_z1: C::Scalar, - /// Params that were used by the verifier - pub params: &'a Params, + allinv: C::Scalar, - /// Scalars produced by the verifier for multiscalar multiplication - pub scalars: Vec, - - /// Points produced by the verifier for multiscalar multiplication - pub bases: Vec, + challenges_sq: Vec, } -impl<'a, C: CurveAffine> Guard<'a, C> { +impl Guard { /// Lets caller supply the challenges and obtain an MSM with updated /// scalars and points. pub fn use_challenges( - &mut self, + mut self, + params: &Params, challenges_sq_packed: Vec, ) -> Result, Error> { + let mut scalars: Vec = vec![]; + let mut bases: Vec = vec![]; + + scalars.extend(&self.msm.other_scalars); + bases.extend(&self.msm.other_bases); + + // - [z2] H + if let Some(h_scalar) = self.msm.h_scalar { + scalars.push(h_scalar); + bases.push(params.h); + } + // - [z1] G let mut allinv = C::Scalar::one(); - let mut challenges_sq = Vec::with_capacity(self.params.k as usize); + let mut challenges_sq = Vec::with_capacity(params.k as usize); - for challenge_sq_packed in challenges_sq_packed { - let challenge_sq: C::Scalar = get_challenge_scalar(challenge_sq_packed); + for challenge_sq_packed in challenges_sq_packed.iter() { + let challenge_sq: C::Scalar = get_challenge_scalar(*challenge_sq_packed); challenges_sq.push(challenge_sq); let challenge = challenge_sq.deterministic_sqrt(); - if challenge.is_none() { - // We didn't sample a square. - return Err(Error::OpeningError); - } let challenge = challenge.unwrap(); let challenge_inv = challenge.invert(); - if bool::from(challenge_inv.is_none()) { - // We sampled zero for some reason, unlikely to happen by - // chance. - return Err(Error::OpeningError); - } let challenge_inv = challenge_inv.unwrap(); allinv *= &challenge_inv; } - self.bases.extend(&self.g); - let mut s = compute_s(&challenges_sq, allinv); - // TODO: parallelize - for s in &mut s { - *s *= &self.neg_z1; - } - self.scalars.extend(s); + let s = compute_s(&challenges_sq, allinv * &self.neg_z1); + scalars.extend(&s); + bases.extend(¶ms.g); - Ok(MSM { - g: self.g.clone(), - h: self.h.clone(), - scalars: self.scalars.clone(), - bases: self.bases.clone(), - }) + self.msm.g_scalars = Some(s); + + Ok(self.msm) } /// Lets caller supply the purported G point and simply appends it to /// return an updated MSM. - pub fn use_s(&mut self, g: Vec, mut s: Vec) -> Result, Error> { - // - [z1] G - self.bases.extend(&g); - for s in &mut s { - *s *= &self.neg_z1; - } - self.scalars.extend(s); + pub fn use_g(mut self, g: C) -> Result, Error> { + &self.msm.other_scalars.push(self.allinv * &self.neg_z1); + &self.msm.other_bases.push(g); - Ok(MSM { - g: self.g.clone(), - h: self.h.clone(), - scalars: self.scalars.clone(), - bases: self.bases.clone(), - }) + Ok(self.msm) } } @@ -426,20 +435,14 @@ fn test_opening_proof() { } else { let opening_proof = opening_proof.unwrap(); // Verify the opening proof - let (challenges, mut guard) = opening_proof - .verify( - ¶ms, - &mut MSM::default(¶ms), - &mut transcript_dup, - x, - &p, - v, - ) + let msm = MSM::default(¶ms); + let (challenges, guard) = opening_proof + .verify(¶ms, msm, &mut transcript_dup, x, &p, v) .unwrap(); - let msm = guard.use_challenges(challenges).unwrap(); + let msm = guard.use_challenges(¶ms, challenges).unwrap(); - assert!(msm.is_zero()); + assert!(msm.is_zero(¶ms)); break; } } diff --git a/src/poly/commitment/verifier.rs b/src/poly/commitment/verifier.rs index 43470cc..e5f897e 100644 --- a/src/poly/commitment/verifier.rs +++ b/src/poly/commitment/verifier.rs @@ -11,12 +11,12 @@ impl OpeningProof { pub fn verify<'a, H: Hasher>( &self, params: &'a Params, - msm: &mut MSM, + mut msm: MSM, transcript: &mut H, x: C::Scalar, p: &C, v: C::Scalar, - ) -> Result<(Vec, Guard<'a, C>), Error> { + ) -> Result<(Vec, Guard), Error> { // Check for well-formedness if self.rounds.len() != params.k as usize { return Err(Error::OpeningError); @@ -43,6 +43,7 @@ impl OpeningProof { let mut challenges_inv = Vec::with_capacity(self.rounds.len()); let mut challenges_sq = Vec::with_capacity(self.rounds.len()); let mut challenges_sq_packed: Vec = Vec::with_capacity(self.rounds.len()); + let mut allinv = C::Scalar::one(); for round in &self.rounds { // Feed L and R into the transcript. @@ -74,13 +75,14 @@ impl OpeningProof { return Err(Error::OpeningError); } let challenge_inv = challenge_inv.unwrap(); + allinv *= &challenge_inv; let challenge_sq_inv = challenge_inv.square(); - msm.scalars.push(challenge_sq); - msm.bases.push(round.0); - msm.scalars.push(challenge_sq_inv); - msm.bases.push(round.1); + msm.other_scalars.push(challenge_sq); + msm.other_bases.push(round.0); + msm.other_scalars.push(challenge_sq_inv); + msm.other_bases.push(round.1); challenges.push(challenge); challenges_inv.push(challenge_inv); @@ -106,7 +108,7 @@ impl OpeningProof { // [c] P + [c * v] U + [c] sum(L_i * u_i^2) + [c] sum(R_i * u_i^-2) + delta - [z1] G - [z1 * b] U - [z2] H // = 0 - for scalar in &mut msm.scalars { + for scalar in &mut msm.other_scalars { *scalar *= &c; } @@ -115,28 +117,25 @@ impl OpeningProof { let neg_z1 = -self.z1; // [c] P - msm.bases.push(*p); - msm.scalars.push(c); + msm.other_bases.push(*p); + msm.other_scalars.push(c); // [c * v] U - [z1 * b] U - msm.bases.push(u); - msm.scalars.push((c * &v) + &(neg_z1 * &b)); + msm.other_bases.push(u); + msm.other_scalars.push((c * &v) + &(neg_z1 * &b)); // delta - msm.bases.push(self.delta); - msm.scalars.push(Field::one()); + msm.other_bases.push(self.delta); + msm.other_scalars.push(Field::one()); - // - [z2] H - msm.bases.push(msm.h); - msm.scalars.push(-self.z2); + // z2 + msm.h_scalar = Some(-self.z2); - let guard = Guard::<'a, _> { - g: msm.g.clone(), - h: msm.h.clone(), + let guard = Guard { + msm, neg_z1, - params, - scalars: msm.scalars.clone(), - bases: msm.bases.clone(), + allinv, + challenges_sq, }; Ok((challenges_sq_packed, guard))