From 8c945507ceca5f4ed6e52da3672ea0308bcac812 Mon Sep 17 00:00:00 2001 From: kilic Date: Tue, 5 Jul 2022 18:33:24 +0300 Subject: [PATCH] fix: integrate verification strategies --- halo2_gadgets/benches/poseidon.rs | 10 +- halo2_proofs/benches/plonk.rs | 5 +- halo2_proofs/src/plonk/verifier.rs | 49 +------- halo2_proofs/src/plonk/verifier/batch.rs | 60 ++++++---- halo2_proofs/src/poly/ipa/msm.rs | 113 +++++++++++------- halo2_proofs/src/poly/ipa/multiopen.rs | 5 +- halo2_proofs/src/poly/ipa/strategy.rs | 60 ++++++++-- .../src/poly/kzg/multiopen/gwc/verifier.rs | 30 +---- .../poly/kzg/multiopen/shplonk/verifier.rs | 35 +----- halo2_proofs/src/poly/kzg/strategy.rs | 103 ++++++++++++++-- halo2_proofs/src/poly/multiopen_test.rs | 70 ++++------- halo2_proofs/src/poly/strategy.rs | 12 +- halo2_proofs/tests/plonk_api.rs | 34 ++---- 13 files changed, 310 insertions(+), 276 deletions(-) diff --git a/halo2_gadgets/benches/poseidon.rs b/halo2_gadgets/benches/poseidon.rs index c73f82a563..4975bdb7b7 100644 --- a/halo2_gadgets/benches/poseidon.rs +++ b/halo2_gadgets/benches/poseidon.rs @@ -5,7 +5,8 @@ use halo2_gadgets::poseidon::{ }; use halo2_proofs::poly::{ commitment::ParamsProver, - ipa::{commitment::IPACommitmentScheme, multiopen::ProverIPA, strategy::BatchVerifier}, + + ipa::{commitment::IPACommitmentScheme, multiopen::ProverIPA, strategy::SingleStrategy}, }; use halo2_proofs::{ circuit::{Layouter, SimpleFloorPlanner, Value}, @@ -252,11 +253,10 @@ fn bench_poseidon( c.bench_function(&verifier_name, |b| { b.iter(|| { use halo2_proofs::poly::VerificationStrategy; - let strategy = BatchVerifier::new(¶ms, OsRng); + let strategy = SingleStrategy::new(¶ms); let mut transcript = Blake2bRead::<_, _, Challenge255<_>>::init(&proof[..]); - let strategy = - verify_proof(¶ms, pk.get_vk(), strategy, &[&[]], &mut transcript).unwrap(); - assert!(strategy.finalize()); + assert!(verify_proof(¶ms, pk.get_vk(), strategy, &[&[]], &mut transcript).is_ok()); + }); }); } diff --git a/halo2_proofs/benches/plonk.rs b/halo2_proofs/benches/plonk.rs index 0511316297..84851d767a 100644 --- a/halo2_proofs/benches/plonk.rs +++ b/halo2_proofs/benches/plonk.rs @@ -7,7 +7,7 @@ use halo2_proofs::circuit::{Cell, Layouter, SimpleFloorPlanner, Value}; use halo2_proofs::plonk::*; use halo2_proofs::poly::ipa::commitment::{IPACommitmentScheme, ParamsIPA}; use halo2_proofs::poly::ipa::multiopen::ProverIPA; -use halo2_proofs::poly::ipa::strategy::BatchVerifier; +use halo2_proofs::poly::ipa::strategy::SingleStrategy; use halo2_proofs::poly::Rotation; use halo2_proofs::transcript::TranscriptReadBuffer; use halo2_proofs::transcript::TranscriptWriterBuffer; @@ -295,8 +295,7 @@ fn criterion_benchmark(c: &mut Criterion) { fn verifier(params: &ParamsIPA, vk: &VerifyingKey, proof: &[u8]) { use halo2_proofs::poly::VerificationStrategy; - let strategy = BatchVerifier::new(params, OsRng); - + let strategy = SingleStrategy::new(¶ms); let mut transcript = Blake2bRead::<_, _, Challenge255<_>>::init(proof); assert!(verify_proof(params, vk, strategy, &[&[]], &mut transcript).is_ok()); } diff --git a/halo2_proofs/src/plonk/verifier.rs b/halo2_proofs/src/plonk/verifier.rs index 6575a73d0a..04c2eca5b7 100644 --- a/halo2_proofs/src/plonk/verifier.rs +++ b/halo2_proofs/src/plonk/verifier.rs @@ -9,7 +9,7 @@ use super::{ }; use crate::arithmetic::{CurveAffine, FieldExt}; use crate::poly::commitment::{CommitmentScheme, Verifier}; -// use crate::poly::VerificationStrategy; +use crate::poly::VerificationStrategy; use crate::poly::{ commitment::{Blind, Params, MSM}, Guard, VerifierQuery, @@ -21,50 +21,6 @@ mod batch; #[cfg(feature = "batch")] pub use batch::BatchVerifier; -/// Trait representing a strategy for verifying Halo 2 proofs. -pub trait VerificationStrategy<'params, C: CurveAffine> { - /// The output type of this verification strategy after processing a proof. - type Output; - - /// Obtains an MSM from the verifier strategy and yields back the strategy's - /// output. - fn process>( - self, - f: impl FnOnce(MSM<'params, C>) -> Result, Error>, - ) -> Result; -} - -/// A verifier that checks a single proof at a time. -#[derive(Debug)] -pub struct SingleVerifier<'params, C: CurveAffine> { - msm: MSM<'params, C>, -} - -impl<'params, C: CurveAffine> SingleVerifier<'params, C> { - /// Constructs a new single proof verifier. - pub fn new(params: &'params Params) -> Self { - SingleVerifier { - msm: MSM::new(params), - } - } -} - -impl<'params, C: CurveAffine> VerificationStrategy<'params, C> for SingleVerifier<'params, C> { - type Output = (); - - fn process>( - self, - f: impl FnOnce(MSM<'params, C>) -> Result, Error>, - ) -> Result { - let guard = f(self.msm)?; - let msm = guard.use_challenges(); - if msm.eval() { - Ok(()) - } else { - Err(Error::ConstraintSystemFailure) - } - } -} use crate::poly::commitment::ParamsVerifier; /// Returns a boolean indicating whether or not the proof is valid @@ -74,8 +30,7 @@ pub fn verify_proof< E: EncodedChallenge, T: TranscriptRead, V: Verifier<'params, Scheme>, - Strategy: VerificationStrategy<'params, Scheme, V, R>, - R: RngCore, + Strategy: VerificationStrategy<'params, Scheme, V>, >( params: &'params Scheme::ParamsVerifier, vk: &VerifyingKey, diff --git a/halo2_proofs/src/plonk/verifier/batch.rs b/halo2_proofs/src/plonk/verifier/batch.rs index b0375ad245..6f47fa1622 100644 --- a/halo2_proofs/src/plonk/verifier/batch.rs +++ b/halo2_proofs/src/plonk/verifier/batch.rs @@ -1,7 +1,10 @@ -use std::{io, marker::PhantomData}; +use std::{ + io::{self, Read}, + marker::PhantomData, +}; use group::ff::Field; -use pasta_curves::arithmetic::CurveAffine; +use halo2curves::CurveAffine; use rand_core::{OsRng, RngCore}; use rayon::iter::{IndexedParallelIterator, IntoParallelIterator, ParallelIterator}; @@ -9,8 +12,16 @@ use super::{verify_proof, VerificationStrategy}; use crate::{ multicore, plonk::{Error, VerifyingKey}, - poly::commitment::{Guard, Params, MSM}, - transcript::{Blake2bRead, EncodedChallenge, TranscriptRead}, + poly::{ + commitment::{Params, MSM}, + ipa::{ + commitment::{IPACommitmentScheme, ParamsIPA, ParamsVerifierIPA}, + msm::MSMIPA, + multiopen::VerifierIPA, + strategy::GuardIPA, + }, + }, + transcript::{Blake2bRead, EncodedChallenge, TranscriptRead, TranscriptReadBuffer}, }; /// A proof verification strategy that returns the proof's MSM. @@ -18,32 +29,37 @@ use crate::{ /// `BatchVerifier` handles the accumulation of the MSMs for the batched proofs. #[derive(Debug)] struct BatchStrategy<'params, C: CurveAffine> { - msm: MSM<'params, C>, + msm: MSMIPA<'params, C>, } -impl<'params, C: CurveAffine> BatchStrategy<'params, C> { - fn new(params: &'params Params) -> Self { +impl<'params, C: CurveAffine> + VerificationStrategy<'params, IPACommitmentScheme, VerifierIPA<'params, C>> + for BatchStrategy<'params, C> +{ + type Output = MSMIPA<'params, C>; + + fn new(params: &'params ParamsVerifierIPA) -> Self { BatchStrategy { - msm: MSM::new(params), + msm: MSMIPA::new(params), } } -} - -impl<'params, C: CurveAffine> VerificationStrategy<'params, C> for BatchStrategy<'params, C> { - type Output = MSM<'params, C>; - fn process>( + fn process( self, - f: impl FnOnce(MSM<'params, C>) -> Result, Error>, + f: impl FnOnce(MSMIPA<'params, C>) -> Result, Error>, ) -> Result { let guard = f(self.msm)?; Ok(guard.use_challenges()) } + + fn finalize(self) -> bool { + unreachable!() + } } #[derive(Debug)] struct BatchItem { - instances: Vec>>, + instances: Vec>>, proof: Vec, } @@ -73,11 +89,15 @@ impl BatchVerifier { /// This uses [`OsRng`] internally instead of taking an `R: RngCore` argument, because /// the internal parallelization requires access to a RNG that is guaranteed to not /// clone its internal state when shared between threads. - pub fn finalize(self, params: &Params, vk: &VerifyingKey) -> bool { + pub fn check>( + self, + params: &ParamsVerifierIPA, + vk: &VerifyingKey, + ) -> bool { fn accumulate_msm<'params, C: CurveAffine>( - mut acc: MSM<'params, C>, - msm: MSM<'params, C>, - ) -> MSM<'params, C> { + mut acc: MSMIPA<'params, C>, + msm: MSMIPA<'params, C>, + ) -> MSMIPA<'params, C> { // 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 with it // to make it true, with high probability. @@ -113,7 +133,7 @@ impl BatchVerifier { .try_reduce(|| params.empty_msm(), |a, b| Ok(accumulate_msm(a, b))); match final_msm { - Ok(msm) => msm.eval(), + Ok(msm) => msm.check(), Err(_) => false, } } diff --git a/halo2_proofs/src/poly/ipa/msm.rs b/halo2_proofs/src/poly/ipa/msm.rs index 9d9a1916d1..63f994b46e 100644 --- a/halo2_proofs/src/poly/ipa/msm.rs +++ b/halo2_proofs/src/poly/ipa/msm.rs @@ -1,20 +1,13 @@ -use super::Params; -use crate::arithmetic::{best_multiexp, CurveAffine}; +use super::commitment::{IPACommitmentScheme, ParamsIPA}; +use crate::arithmetic::{best_multiexp, parallelize, CurveAffine}; +use crate::poly::{ + commitment::{CommitmentScheme, Params, MSM}, + ipa::commitment::ParamsVerifierIPA, +}; use ff::Field; use group::Group; - use std::collections::BTreeMap; -use crate::{ - arithmetic::{best_multiexp, parallelize, CurveAffine}, - poly::{ - commitment::{CommitmentScheme, Params, MSM}, - ipa::commitment::ParamsVerifierIPA, - }, -}; - -use super::commitment::{IPACommitmentScheme, ParamsIPA}; - /// A multiscalar multiplication in the polynomial commitment scheme #[derive(Debug, Clone)] pub struct MSMIPA<'params, C: CurveAffine> { @@ -72,10 +65,13 @@ impl<'a, C: CurveAffine> MSMIPA<'a, C> { self.add_to_u_scalar(*u_scalar); } } +} - /// Add arbitrary term (the scalar and the point) - pub fn append_term(&mut self, scalar: C::Scalar, point: C) { +impl<'a, C: CurveAffine> MSM for MSMIPA<'a, C> { + fn append_term(&mut self, scalar: C::Scalar, point: C::Curve) { if !bool::from(point.is_identity()) { + use group::Curve; + let point = point.to_affine(); let xy = point.coordinates().unwrap(); let x = *xy.x(); let y = *xy.y(); @@ -94,9 +90,33 @@ impl<'a, C: CurveAffine> MSMIPA<'a, C> { } } + /// Add another multiexp into this one fn add_msm(&mut self, other: &Self) { - self.other_scalars.extend(other.scalars().iter()); - self.other_bases.extend(other.bases().iter()); + for (x, (scalar, y)) in other.other.iter() { + self.other + .entry(*x) + .and_modify(|(our_scalar, our_y)| { + if our_y == y { + *our_scalar += *scalar; + } else { + assert!(*our_y == -*y); + *our_scalar -= *scalar; + } + }) + .or_insert((*scalar, *y)); + } + + if let Some(g_scalars) = &other.g_scalars { + self.add_to_g_scalars(g_scalars); + } + + if let Some(w_scalar) = &other.w_scalar { + self.add_to_w_scalar(*w_scalar); + } + + if let Some(u_scalar) = &other.u_scalar { + self.add_to_u_scalar(*u_scalar); + } } fn scale(&mut self, factor: C::Scalar) { @@ -124,7 +144,7 @@ impl<'a, C: CurveAffine> MSMIPA<'a, C> { + self.u_scalar.map(|_| 1).unwrap_or(0) + self.other.len(); let mut scalars: Vec = Vec::with_capacity(len); - let mut bases: Vec = Vec::with_capacity(len); + let mut bases: Vec = Vec::with_capacity(len); scalars.extend(self.other.values().map(|(scalar, _)| scalar)); bases.extend( @@ -135,34 +155,33 @@ impl<'a, C: CurveAffine> MSMIPA<'a, C> { if let Some(w_scalar) = self.w_scalar { scalars.push(w_scalar); - bases.push(self.params.w.into()); + bases.push(self.params.w); } if let Some(u_scalar) = self.u_scalar { scalars.push(u_scalar); - bases.push(self.params.u.into()); + bases.push(self.params.u); } if let Some(g_scalars) = &self.g_scalars { scalars.extend(g_scalars); - let g: Vec = self.params.g.iter().map(|g| (*g).into()).collect(); - bases.extend(g); + bases.extend(self.params.g.iter()); } assert_eq!(scalars.len(), len); - use group::Curve; - let mut normalized = vec![C::identity(); scalars.len()]; - C::Curve::batch_normalize(&bases[..], &mut normalized); - best_multiexp(&scalars, &normalized[..]) + best_multiexp(&scalars, &bases) } fn bases(&self) -> Vec { - self.other_bases.clone() + self.other + .iter() + .map(|(x, (_, y))| C::from_xy(*x, *y).unwrap().into()) + .collect() } fn scalars(&self) -> Vec { - self.other_scalars.clone() + self.other.values().map(|(scalar, _)| *scalar).collect() } } @@ -203,49 +222,57 @@ impl<'a, C: CurveAffine> MSMIPA<'a, C> { #[cfg(test)] mod tests { - use crate::poly::commitment::{Params, MSM}; + use super::ParamsIPA; + use crate::poly::commitment::ParamsProver; + use crate::poly::{ + commitment::{Params, MSM}, + ipa::msm::MSMIPA, + }; use group::Curve; - use pasta_curves::{arithmetic::CurveAffine, EpAffine, Fp, Fq}; + use halo2curves::{ + pasta::{Ep, EpAffine, Fp, Fq}, + CurveAffine, + }; #[test] fn msm_arithmetic() { - let base = EpAffine::from_xy(-Fp::one(), Fp::from(2)).unwrap(); - let base_viol = (base + base).to_affine(); + let base: Ep = EpAffine::from_xy(-Fp::one(), Fp::from(2)).unwrap().into(); + let base_viol = base + base; - let params = Params::new(4); - let mut a: MSM = MSM::new(¶ms); + let params = ParamsIPA::new(4); + let mut a: MSMIPA = MSMIPA::new(¶ms); a.append_term(Fq::one(), base); // a = [1] P - assert!(!a.clone().eval()); + assert!(!a.clone().check()); a.append_term(Fq::one(), base); // a = [1+1] P - assert!(!a.clone().eval()); + assert!(!a.clone().check()); a.append_term(-Fq::one(), base_viol); // a = [1+1] P + [-1] 2P - assert!(a.clone().eval()); + assert!(a.clone().check()); let b = a.clone(); // Append a point that is the negation of an existing one. a.append_term(Fq::from(4), -base); // a = [1+1-4] P + [-1] 2P - assert!(!a.clone().eval()); + assert!(!a.clone().check()); a.append_term(Fq::from(2), base_viol); // a = [1+1-4] P + [-1+2] 2P - assert!(a.clone().eval()); + assert!(a.clone().check()); // Add two MSMs with common bases. a.scale(Fq::from(3)); a.add_msm(&b); // a = [3*(1+1)+(1+1-4)] P + [3*(-1)+(-1+2)] 2P - assert!(a.clone().eval()); + assert!(a.clone().check()); - let mut c: MSM = MSM::new(¶ms); + let mut c: MSMIPA = MSMIPA::new(¶ms); c.append_term(Fq::from(2), base); c.append_term(Fq::one(), -base_viol); // c = [2] P + [1] (-2P) - assert!(c.clone().eval()); + assert!(c.clone().check()); // Add two MSMs with bases that differ only in sign. a.add_msm(&c); - assert!(a.eval()); + assert!(a.check()); } } diff --git a/halo2_proofs/src/poly/ipa/multiopen.rs b/halo2_proofs/src/poly/ipa/multiopen.rs index a1a37d48a1..3022466981 100644 --- a/halo2_proofs/src/poly/ipa/multiopen.rs +++ b/halo2_proofs/src/poly/ipa/multiopen.rs @@ -11,10 +11,7 @@ use crate::{ plonk::Error, poly::{ commitment::{Blind, Params, Verifier, MSM}, - ipa::{ - commitment::ParamsIPA, - strategy::{BatchVerifier, GuardIPA}, - }, + ipa::{commitment::ParamsIPA, strategy::GuardIPA}, query::Query, Coeff, Polynomial, }, diff --git a/halo2_proofs/src/poly/ipa/strategy.rs b/halo2_proofs/src/poly/ipa/strategy.rs index 7424e4e4a7..cdb18b7a78 100644 --- a/halo2_proofs/src/poly/ipa/strategy.rs +++ b/halo2_proofs/src/poly/ipa/strategy.rs @@ -17,7 +17,7 @@ use crate::{ use ff::Field; use group::Curve; use halo2curves::CurveAffine; -use rand_core::RngCore; +use rand_core::{OsRng, RngCore}; /// Wrapper for verification accumulator #[derive(Debug, Clone)] @@ -68,21 +68,19 @@ impl<'params, C: CurveAffine> GuardIPA<'params, C> { /// A verifier that checks multiple proofs in a batch. #[derive(Debug)] -pub struct BatchVerifier<'params, C: CurveAffine, R: RngCore> { +pub struct AccumulatorStrategy<'params, C: CurveAffine> { msm_accumulator: MSMIPA<'params, C>, - rng: R, } -impl<'params, C: CurveAffine, R: RngCore> - VerificationStrategy<'params, IPACommitmentScheme, VerifierIPA<'params, C>, R> - for BatchVerifier<'params, C, R> +impl<'params, C: CurveAffine> + VerificationStrategy<'params, IPACommitmentScheme, VerifierIPA<'params, C>> + for AccumulatorStrategy<'params, C> { type Output = Self; - fn new(params: &'params ParamsIPA, rng: R) -> Self { - BatchVerifier { + fn new(params: &'params ParamsIPA) -> Self { + AccumulatorStrategy { msm_accumulator: MSMIPA::new(params), - rng, } } @@ -90,12 +88,11 @@ impl<'params, C: CurveAffine, R: RngCore> mut self, f: impl FnOnce(MSMIPA<'params, C>) -> Result, Error>, ) -> Result { - self.msm_accumulator.scale(C::Scalar::random(&mut self.rng)); + self.msm_accumulator.scale(C::Scalar::random(OsRng)); let guard = f(self.msm_accumulator)?; Ok(Self { msm_accumulator: guard.use_challenges(), - rng: self.rng, }) } @@ -109,6 +106,47 @@ impl<'params, C: CurveAffine, R: RngCore> } } +/// A verifier that checks single proof +#[derive(Debug)] +pub struct SingleStrategy<'params, C: CurveAffine> { + msm: MSMIPA<'params, C>, +} + +impl<'params, C: CurveAffine> + VerificationStrategy<'params, IPACommitmentScheme, VerifierIPA<'params, C>> + for SingleStrategy<'params, C> +{ + type Output = (); + + fn new(params: &'params ParamsIPA) -> Self { + SingleStrategy { + msm: MSMIPA::new(params), + } + } + + fn process( + self, + f: impl FnOnce(MSMIPA<'params, C>) -> Result, Error>, + ) -> Result { + let guard = f(self.msm)?; + let msm = guard.use_challenges(); + if msm.check() { + Ok(()) + } else { + Err(Error::ConstraintSystemFailure) + } + } + + /// Finalizes the batch and checks its validity. + /// + /// Returns `false` if *some* proof was invalid. If the caller needs to identify + /// specific failing proofs, it must re-process the proofs separately. + #[must_use] + fn finalize(self) -> bool { + unreachable!() + } +} + /// Computes the coefficients of $g(X) = \prod\limits_{i=0}^{k-1} (1 + u_{k - 1 - i} X^{2^i})$. fn compute_s(u: &[F], init: F) -> Vec { assert!(!u.is_empty()); diff --git a/halo2_proofs/src/poly/kzg/multiopen/gwc/verifier.rs b/halo2_proofs/src/poly/kzg/multiopen/gwc/verifier.rs index 6abf94e580..8001c563c4 100644 --- a/halo2_proofs/src/poly/kzg/multiopen/gwc/verifier.rs +++ b/halo2_proofs/src/poly/kzg/multiopen/gwc/verifier.rs @@ -9,7 +9,7 @@ use crate::poly::commitment::Verifier; use crate::poly::commitment::MSM; use crate::poly::kzg::commitment::{KZGCommitmentScheme, ParamsKZG}; use crate::poly::kzg::msm::{DualMSM, MSMKZG}; -use crate::poly::kzg::strategy::{BatchVerifier, GuardKZG}; +use crate::poly::kzg::strategy::{AccumulatorStrategy, GuardKZG, SingleStrategy}; use crate::poly::query::Query; use crate::poly::query::{CommitmentReference, VerifierQuery}; use crate::poly::strategy::VerificationStrategy; @@ -22,7 +22,7 @@ use crate::transcript::{EncodedChallenge, TranscriptRead}; use ff::Field; use group::Group; use halo2curves::pairing::{Engine, MillerLoopResult, MultiMillerLoop}; -use rand_core::RngCore; +use rand_core::OsRng; #[derive(Debug)] /// Concrete KZG verifier with GWC variant @@ -117,29 +117,3 @@ impl<'params, E: MultiMillerLoop + Debug> Verifier<'params, KZGCommitmentScheme< Ok(Self::Guard::new(msm_accumulator)) } } - -impl<'params, E: MultiMillerLoop + Debug, R: RngCore> - VerificationStrategy<'params, KZGCommitmentScheme, VerifierGWC<'params, E>, R> - for BatchVerifier<'params, E, R> -{ - type Output = Self; - - fn new(params: &'params ParamsKZG, rng: R) -> Self { - BatchVerifier::new(params, rng) - } - - fn process( - mut self, - f: impl FnOnce(DualMSM<'params, E>) -> Result, crate::plonk::Error>, - ) -> Result { - self.msm_accumulator.scale(E::Scalar::random(&mut self.rng)); - - // Guard is updated with new msm contributions - let guard = f(self.msm_accumulator)?; - Ok(BatchVerifier::with(guard.msm_accumulator, self.rng)) - } - - fn finalize(self) -> bool { - self.msm_accumulator.check() - } -} diff --git a/halo2_proofs/src/poly/kzg/multiopen/shplonk/verifier.rs b/halo2_proofs/src/poly/kzg/multiopen/shplonk/verifier.rs index 35b21fc45e..9554fd139b 100644 --- a/halo2_proofs/src/poly/kzg/multiopen/shplonk/verifier.rs +++ b/halo2_proofs/src/poly/kzg/multiopen/shplonk/verifier.rs @@ -11,7 +11,7 @@ use crate::poly::commitment::MSM; use crate::poly::kzg::commitment::{KZGCommitmentScheme, ParamsKZG}; use crate::poly::kzg::msm::DualMSM; use crate::poly::kzg::msm::{PreMSM, MSMKZG}; -use crate::poly::kzg::strategy::{BatchVerifier, GuardKZG}; +use crate::poly::kzg::strategy::{AccumulatorStrategy, GuardKZG, SingleStrategy}; use crate::poly::query::Query; use crate::poly::query::{CommitmentReference, VerifierQuery}; use crate::poly::strategy::VerificationStrategy; @@ -23,7 +23,7 @@ use crate::transcript::{EncodedChallenge, TranscriptRead}; use ff::Field; use group::Group; use halo2curves::pairing::{Engine, MillerLoopResult, MultiMillerLoop}; -use rand_core::RngCore; +use rand_core::OsRng; use std::ops::MulAssign; /// Concrete KZG multiopen verifier with SHPLONK variant @@ -100,7 +100,8 @@ impl<'params, E: MultiMillerLoop + Debug> Verifier<'params, KZGCommitmentScheme< let inner_contrib = match commitment_data.get() { CommitmentReference::Commitment(c) => (*c).into(), // TODO: we should support one more nested degree to append - // folded commitments to the inner_msm + // folded commitments to the inner_msm. + // Then remove MSM::check function CommitmentReference::MSM(msm) => msm.eval(), }; inner_msm.append_term(E::Scalar::one(), inner_contrib); @@ -127,31 +128,3 @@ impl<'params, E: MultiMillerLoop + Debug> Verifier<'params, KZGCommitmentScheme< Ok(Self::Guard::new(msm_accumulator)) } } - -impl<'params, E: MultiMillerLoop + Debug, R: RngCore> - VerificationStrategy<'params, KZGCommitmentScheme, VerifierSHPLONK<'params, E>, R> - for BatchVerifier<'params, E, R> -{ - type Output = Self; - - /// Constructs a new batch verifier. - fn new(params: &'params ParamsKZG, rng: R) -> Self { - BatchVerifier::new(params, rng) - } - - fn process( - mut self, - - f: impl FnOnce(DualMSM<'params, E>) -> Result, crate::plonk::Error>, - ) -> Result { - self.msm_accumulator.scale(E::Scalar::random(&mut self.rng)); - - // Guard is updated with new msm contributions - let guard = f(self.msm_accumulator)?; - Ok(BatchVerifier::with(guard.msm_accumulator, self.rng)) - } - - fn finalize(self) -> bool { - self.msm_accumulator.check() - } -} diff --git a/halo2_proofs/src/poly/kzg/strategy.rs b/halo2_proofs/src/poly/kzg/strategy.rs index 4d63fd3554..896760067d 100644 --- a/halo2_proofs/src/poly/kzg/strategy.rs +++ b/halo2_proofs/src/poly/kzg/strategy.rs @@ -20,7 +20,7 @@ use halo2curves::{ pairing::{Engine, MillerLoopResult, MultiMillerLoop}, CurveAffine, }; -use rand_core::RngCore; +use rand_core::OsRng; /// Wrapper for linear verification accumulator #[derive(Debug, Clone)] @@ -42,25 +42,106 @@ impl<'params, E: MultiMillerLoop + Debug> GuardKZG<'params, E> { /// A verifier that checks multiple proofs in a batch #[derive(Clone, Debug)] -pub struct BatchVerifier<'params, E: Engine, R: RngCore> { +pub struct AccumulatorStrategy<'params, E: Engine> { pub(crate) msm_accumulator: DualMSM<'params, E>, - pub(crate) rng: R, } -impl<'params, E: MultiMillerLoop + Debug, R: RngCore> BatchVerifier<'params, E, R> { +impl<'params, E: MultiMillerLoop + Debug> AccumulatorStrategy<'params, E> { /// Constructs an empty batch verifier - pub fn new(params: &'params ParamsKZG, rng: R) -> Self { - BatchVerifier { + pub fn new(params: &'params ParamsKZG) -> Self { + AccumulatorStrategy { msm_accumulator: DualMSM::new(params), - rng, } } /// Constructs and initialized new batch verifier - pub fn with(msm_accumulator: DualMSM<'params, E>, rng: R) -> Self { - BatchVerifier { - msm_accumulator, - rng, + pub fn with(msm_accumulator: DualMSM<'params, E>) -> Self { + AccumulatorStrategy { msm_accumulator } + } +} + +/// A verifier that checks a single proof +#[derive(Clone, Debug)] +pub struct SingleStrategy<'params, E: Engine> { + pub(crate) msm: DualMSM<'params, E>, +} + +impl<'params, E: MultiMillerLoop + Debug> SingleStrategy<'params, E> { + /// Constructs an empty batch verifier + pub fn new(params: &'params ParamsKZG) -> Self { + SingleStrategy { + msm: DualMSM::new(params), } } } + +impl< + 'params, + E: MultiMillerLoop + Debug, + V: Verifier< + 'params, + KZGCommitmentScheme, + MSMAccumulator = DualMSM<'params, E>, + Guard = GuardKZG<'params, E>, + >, + > VerificationStrategy<'params, KZGCommitmentScheme, V> for AccumulatorStrategy<'params, E> +{ + type Output = Self; + + fn new(params: &'params ParamsKZG) -> Self { + AccumulatorStrategy::new(params) + } + + fn process( + mut self, + f: impl FnOnce(V::MSMAccumulator) -> Result, + ) -> Result { + self.msm_accumulator.scale(E::Scalar::random(OsRng)); + + // Guard is updated with new msm contributions + let guard = f(self.msm_accumulator)?; + Ok(Self { + msm_accumulator: guard.msm_accumulator, + }) + } + + fn finalize(self) -> bool { + self.msm_accumulator.check() + } +} + +impl< + 'params, + E: MultiMillerLoop + Debug, + V: Verifier< + 'params, + KZGCommitmentScheme, + MSMAccumulator = DualMSM<'params, E>, + Guard = GuardKZG<'params, E>, + >, + > VerificationStrategy<'params, KZGCommitmentScheme, V> for SingleStrategy<'params, E> +{ + type Output = (); + + fn new(params: &'params ParamsKZG) -> Self { + Self::new(params) + } + + fn process( + self, + f: impl FnOnce(V::MSMAccumulator) -> Result, + ) -> Result { + // Guard is updated with new msm contributions + let guard = f(self.msm)?; + let msm = guard.msm_accumulator; + if msm.check() { + Ok(()) + } else { + Err(Error::ConstraintSystemFailure) + } + } + + fn finalize(self) -> bool { + unreachable!(); + } +} diff --git a/halo2_proofs/src/poly/multiopen_test.rs b/halo2_proofs/src/poly/multiopen_test.rs index 44d4cf9b10..66836e4c41 100644 --- a/halo2_proofs/src/poly/multiopen_test.rs +++ b/halo2_proofs/src/poly/multiopen_test.rs @@ -30,21 +30,19 @@ mod test { fn test_roundtrip_ipa() { use crate::poly::ipa::commitment::{IPACommitmentScheme, ParamsIPA}; use crate::poly::ipa::multiopen::{ProverIPA, VerifierIPA}; - use crate::poly::ipa::strategy::BatchVerifier; + use crate::poly::ipa::strategy::AccumulatorStrategy; use halo2curves::pasta::{Ep, EqAffine, Fp}; const K: u32 = 4; let params = ParamsIPA::::new(K); - let rng = OsRng; let proof = create_proof::< IPACommitmentScheme, Blake2bWrite<_, _, Challenge255<_>>, ProverIPA<_>, _, - _, - >(rng, ¶ms); + >(¶ms); let verifier_params = params.verifier_params(); @@ -52,42 +50,37 @@ mod test { IPACommitmentScheme, Blake2bRead<_, _, Challenge255<_>>, VerifierIPA<_>, - BatchVerifier<_, _>, - _, + AccumulatorStrategy<_>, _, - >(rng, verifier_params, &proof[..], false); + >(verifier_params, &proof[..], false); verify::< IPACommitmentScheme, Blake2bRead<_, _, Challenge255<_>>, VerifierIPA<_>, - BatchVerifier<_, _>, - _, + AccumulatorStrategy<_>, _, - >(rng, verifier_params, &proof[..], true); + >(verifier_params, &proof[..], true); } #[test] fn test_roundtrip_gwc() { use crate::poly::kzg::commitment::{KZGCommitmentScheme, ParamsKZG}; use crate::poly::kzg::multiopen::{ProverGWC, VerifierGWC}; - use crate::poly::kzg::strategy::BatchVerifier; + use crate::poly::kzg::strategy::AccumulatorStrategy; use halo2curves::bn256::{Bn256, G1Affine}; use halo2curves::pairing::Engine; const K: u32 = 4; let params = ParamsKZG::::new(K); - let rng = OsRng; - let proof = create_proof::<_, Blake2bWrite<_, _, Challenge255<_>>, ProverGWC<_>, _, _>( - rng, ¶ms, - ); + let proof = + create_proof::<_, Blake2bWrite<_, _, Challenge255<_>>, ProverGWC<_>, _>(¶ms); let verifier_params = params.verifier_params(); - verify::<_, Blake2bRead<_, _, Challenge255<_>>, VerifierGWC<_>, BatchVerifier<_, _>, _, _>( - rng, + verify::<_, Blake2bRead<_, _, Challenge255<_>>, VerifierGWC<_>, AccumulatorStrategy<_>, _>( verifier_params, &proof[..], false, @@ -97,32 +90,29 @@ mod test { KZGCommitmentScheme, Blake2bRead<_, _, Challenge255<_>>, VerifierGWC<_>, - BatchVerifier<_, _>, - _, + AccumulatorStrategy<_>, _, - >(rng, verifier_params, &proof[..], true); + >(verifier_params, &proof[..], true); } #[test] fn test_roundtrip_shplonk() { use crate::poly::kzg::commitment::{KZGCommitmentScheme, ParamsKZG}; use crate::poly::kzg::multiopen::{ProverSHPLONK, VerifierSHPLONK}; - use crate::poly::kzg::strategy::BatchVerifier; + use crate::poly::kzg::strategy::AccumulatorStrategy; use halo2curves::bn256::{Bn256, G1Affine}; use halo2curves::pairing::Engine; const K: u32 = 4; let params = ParamsKZG::::new(K); - let rng = OsRng; let proof = create_proof::< KZGCommitmentScheme, Blake2bWrite<_, _, Challenge255<_>>, ProverSHPLONK<_>, _, - _, - >(rng, ¶ms); + >(¶ms); let verifier_params = params.verifier_params(); @@ -130,19 +120,17 @@ mod test { KZGCommitmentScheme, Blake2bRead<_, _, Challenge255<_>>, VerifierSHPLONK<_>, - BatchVerifier<_, _>, + AccumulatorStrategy<_>, _, - _, - >(rng, verifier_params, &proof[..], false); + >(verifier_params, &proof[..], false); verify::< KZGCommitmentScheme, Blake2bRead<_, _, Challenge255<_>>, VerifierSHPLONK<_>, - BatchVerifier<_, _>, - _, + AccumulatorStrategy<_>, _, - >(rng, verifier_params, &proof[..], true); + >(verifier_params, &proof[..], true); } fn verify< @@ -151,18 +139,13 @@ mod test { Scheme: CommitmentScheme, TranscriptRead: TranscriptReadBuffer<&'a [u8], Scheme::Curve, Ch>, Verifier: _Verifier<'params, Scheme>, - Strategy: VerificationStrategy<'params, Scheme, Verifier, R, Output = Strategy>, - Ch, - R, + Strategy: VerificationStrategy<'params, Scheme, Verifier, Output = Strategy>, + Ch: EncodedChallenge, >( - rng: R, params: &'params Scheme::ParamsVerifier, proof: &'a [u8], should_fail: bool, - ) where - Ch: EncodedChallenge, - R: RngCore + Copy, - { + ) { let verifier = Verifier::new(params); let mut transcript = TranscriptRead::init(proof); @@ -195,7 +178,7 @@ mod test { }; { - let strategy = Strategy::new(params, rng); + let strategy = Strategy::new(params); let strategy = strategy .process(|msm_accumulator| { verifier @@ -214,14 +197,11 @@ mod test { TranscriptWrite: TranscriptWriterBuffer, Scheme::Curve, Ch>, Prover: _Prover<'params, Scheme>, Ch, - Rng, >( - mut rng: Rng, params: &'params Scheme::ParamsProver, ) -> Vec where Ch: EncodedChallenge, - Rng: RngCore, { let domain = EvaluationDomain::new(1, params.k()); @@ -248,7 +228,7 @@ mod test { let mut transcript = TranscriptWrite::init(vec![]); - let blind = Blind::new(&mut rng); + let blind = Blind::new(&mut OsRng); let a = params.commit(&ax, blind).to_affine(); let b = params.commit(&bx, blind).to_affine(); let c = params.commit(&cx, blind).to_affine(); @@ -288,7 +268,9 @@ mod test { .to_vec(); let prover = Prover::new(params); - prover.create_proof(rng, &mut transcript, queries).unwrap(); + prover + .create_proof(&mut OsRng, &mut transcript, queries) + .unwrap(); transcript.finalize() } diff --git a/halo2_proofs/src/poly/strategy.rs b/halo2_proofs/src/poly/strategy.rs index 678cdf5452..a7310f3eff 100644 --- a/halo2_proofs/src/poly/strategy.rs +++ b/halo2_proofs/src/poly/strategy.rs @@ -1,3 +1,4 @@ +use halo2curves::CurveAffine; use rand_core::RngCore; use super::commitment::{CommitmentScheme, Verifier, MSM}; @@ -10,22 +11,17 @@ use crate::{ /// verification strategies such as aggregation and recursion. pub trait Guard { /// Multi scalar engine which is not evaluated yet. + type MSMAccumulator; } /// Trait representing a strategy for verifying Halo 2 proofs. -pub trait VerificationStrategy< - 'params, - Scheme: CommitmentScheme, - V: Verifier<'params, Scheme>, - R: RngCore, -> -{ +pub trait VerificationStrategy<'params, Scheme: CommitmentScheme, V: Verifier<'params, Scheme>> { /// The output type of this verification strategy after processing a proof. type Output; /// Creates new verification strategy instance - fn new(params: &'params Scheme::ParamsVerifier, rng: R) -> Self; + fn new(params: &'params Scheme::ParamsVerifier) -> Self; /// Obtains an MSM from the verifier strategy and yields back the strategy's /// output. diff --git a/halo2_proofs/tests/plonk_api.rs b/halo2_proofs/tests/plonk_api.rs index a0f7187c7b..06daeea277 100644 --- a/halo2_proofs/tests/plonk_api.rs +++ b/halo2_proofs/tests/plonk_api.rs @@ -525,24 +525,19 @@ fn plonk_api() { Scheme: CommitmentScheme, Verifier: _Verifier<'params, Scheme>, TranscriptRead: TranscriptReadBuffer<&'a [u8], Scheme::Curve, Ch>, - Strategy: VerificationStrategy<'params, Scheme, Verifier, Rng, Output = Strategy>, - Ch, - Rng, + Strategy: VerificationStrategy<'params, Scheme, Verifier, Output = Strategy>, + Ch: EncodedChallenge, >( - rng: Rng, params_verifier: &'params Scheme::ParamsVerifier, vk: &VerifyingKey, proof: &'a [u8], - ) where - Ch: EncodedChallenge, - Rng: RngCore + Copy, - { + ) { let (_, instance, _) = common!(Scheme); let pubinputs = vec![instance]; let mut transcript = TranscriptRead::init(proof); - let strategy = Strategy::new(params_verifier, rng); + let strategy = Strategy::new(params_verifier); let strategy = verify_plonk_proof( params_verifier, vk, @@ -558,7 +553,7 @@ fn plonk_api() { fn test_plonk_api_gwc() { use halo2_proofs::poly::kzg::commitment::{KZGCommitmentScheme, ParamsKZG}; use halo2_proofs::poly::kzg::multiopen::{ProverGWC, VerifierGWC}; - use halo2_proofs::poly::kzg::strategy::BatchVerifier; + use halo2_proofs::poly::kzg::strategy::AccumulatorStrategy; use halo2curves::bn256::Bn256; type Scheme = KZGCommitmentScheme; @@ -579,16 +574,15 @@ fn plonk_api() { _, VerifierGWC<_>, Blake2bRead<_, _, Challenge255<_>>, - BatchVerifier<_, _>, - _, + AccumulatorStrategy<_>, _, - >(rng, verifier_params, pk.get_vk(), &proof[..]); + >(verifier_params, pk.get_vk(), &proof[..]); } fn test_plonk_api_shplonk() { use halo2_proofs::poly::kzg::commitment::{KZGCommitmentScheme, ParamsKZG}; use halo2_proofs::poly::kzg::multiopen::{ProverSHPLONK, VerifierSHPLONK}; - use halo2_proofs::poly::kzg::strategy::BatchVerifier; + use halo2_proofs::poly::kzg::strategy::AccumulatorStrategy; use halo2curves::bn256::Bn256; type Scheme = KZGCommitmentScheme; @@ -609,16 +603,15 @@ fn plonk_api() { _, VerifierSHPLONK<_>, Blake2bRead<_, _, Challenge255<_>>, - BatchVerifier<_, _>, + AccumulatorStrategy<_>, _, - _, - >(rng, verifier_params, pk.get_vk(), &proof[..]); + >(verifier_params, pk.get_vk(), &proof[..]); } fn test_plonk_api_ipa() { use halo2_proofs::poly::ipa::commitment::{IPACommitmentScheme, ParamsIPA}; use halo2_proofs::poly::ipa::multiopen::{ProverIPA, VerifierIPA}; - use halo2_proofs::poly::ipa::strategy::BatchVerifier; + use halo2_proofs::poly::ipa::strategy::AccumulatorStrategy; use halo2curves::pasta::EqAffine; type Scheme = IPACommitmentScheme; @@ -639,10 +632,9 @@ fn plonk_api() { _, VerifierIPA<_>, Blake2bRead<_, _, Challenge255<_>>, - BatchVerifier<_, _>, - _, + AccumulatorStrategy<_>, _, - >(rng, verifier_params, pk.get_vk(), &proof[..]); + >(verifier_params, pk.get_vk(), &proof[..]); // Check that the verification key has not changed unexpectedly {