diff --git a/halo2_backend/src/helpers.rs b/halo2_backend/src/helpers.rs index 3cd00b84ad..fa4936dffb 100644 --- a/halo2_backend/src/helpers.rs +++ b/halo2_backend/src/helpers.rs @@ -20,7 +20,6 @@ pub enum SerdeFormat { RawBytesUnchecked, } -// Keep this trait for compatibility with IPA serialization pub trait CurveRead: CurveAffine { /// Reads a compressed element from the buffer and attempts to parse it /// using `from_bytes`. diff --git a/halo2_backend/src/plonk/lookup/prover.rs b/halo2_backend/src/plonk/lookup/prover.rs index 9f25fe9f13..69535a7289 100644 --- a/halo2_backend/src/plonk/lookup/prover.rs +++ b/halo2_backend/src/plonk/lookup/prover.rs @@ -30,21 +30,16 @@ pub(in crate::plonk) struct Permuted { compressed_input_expression: Polynomial, permuted_input_expression: Polynomial, permuted_input_poly: Polynomial, - permuted_input_blind: Blind, compressed_table_expression: Polynomial, permuted_table_expression: Polynomial, permuted_table_poly: Polynomial, - permuted_table_blind: Blind, } #[derive(Debug)] pub(in crate::plonk) struct Committed { pub(in crate::plonk) permuted_input_poly: Polynomial, - permuted_input_blind: Blind, pub(in crate::plonk) permuted_table_poly: Polynomial, - permuted_table_blind: Blind, pub(in crate::plonk) product_poly: Polynomial, - product_blind: Blind, } pub(in crate::plonk) struct Evaluated { @@ -130,15 +125,15 @@ where let poly = pk.vk.domain.lagrange_to_coeff(values.clone()); let blind = Blind(C::Scalar::random(&mut rng)); let commitment = params.commit_lagrange(&engine.msm_backend, values, blind); - (poly, blind, commitment) + (poly, commitment) }; // Commit to permuted input expression - let (permuted_input_poly, permuted_input_blind, permuted_input_commitment_projective) = + let (permuted_input_poly, permuted_input_commitment_projective) = commit_values(&permuted_input_expression); // Commit to permuted table expression - let (permuted_table_poly, permuted_table_blind, permuted_table_commitment_projective) = + let (permuted_table_poly, permuted_table_commitment_projective) = commit_values(&permuted_table_expression); let [permuted_input_commitment, permuted_table_commitment] = { @@ -163,11 +158,9 @@ where compressed_input_expression, permuted_input_expression, permuted_input_poly, - permuted_input_blind, compressed_table_expression, permuted_table_expression, permuted_table_poly, - permuted_table_blind, }) } @@ -313,11 +306,8 @@ impl Permuted { Ok(Committed:: { permuted_input_poly: self.permuted_input_poly, - permuted_input_blind: self.permuted_input_blind, permuted_table_poly: self.permuted_table_poly, - permuted_table_blind: self.permuted_table_blind, product_poly: z, - product_blind, }) } } @@ -368,31 +358,26 @@ impl Evaluated { .chain(Some(ProverQuery { point: *x, poly: &self.constructed.product_poly, - blind: self.constructed.product_blind, })) // Open lookup input commitments at x .chain(Some(ProverQuery { point: *x, poly: &self.constructed.permuted_input_poly, - blind: self.constructed.permuted_input_blind, })) // Open lookup table commitments at x .chain(Some(ProverQuery { point: *x, poly: &self.constructed.permuted_table_poly, - blind: self.constructed.permuted_table_blind, })) // Open lookup input commitments at x_inv .chain(Some(ProverQuery { point: x_inv, poly: &self.constructed.permuted_input_poly, - blind: self.constructed.permuted_input_blind, })) // Open lookup product commitments at x_next .chain(Some(ProverQuery { point: x_next, poly: &self.constructed.product_poly, - blind: self.constructed.product_blind, })) } } diff --git a/halo2_backend/src/plonk/permutation/prover.rs b/halo2_backend/src/plonk/permutation/prover.rs index 854d7960bf..3d40c4130d 100644 --- a/halo2_backend/src/plonk/permutation/prover.rs +++ b/halo2_backend/src/plonk/permutation/prover.rs @@ -28,7 +28,6 @@ use halo2_middleware::poly::Rotation; /// It stores a single `Z_P` in [permutation argument specification](https://zcash.github.io/halo2/design/proving-system/permutation.html#argument-specification). pub(crate) struct CommittedSet { pub(crate) permutation_product_poly: Polynomial, - permutation_product_blind: Blind, } /// Set of permutation product polynomials, which have been **committed**. @@ -181,7 +180,6 @@ pub(in crate::plonk) fn permutation_commit< let permutation_product_commitment = params .commit_lagrange(&engine.msm_backend, &z, blind) .to_affine(); - let permutation_product_blind = blind; let permutation_product_poly = domain.lagrange_to_coeff(z); // Hash the permutation product commitment @@ -189,7 +187,6 @@ pub(in crate::plonk) fn permutation_commit< sets.push(CommittedSet { permutation_product_poly, - permutation_product_blind, }); } @@ -201,11 +198,9 @@ impl super::ProvingKey { &self, x: ChallengeX, ) -> impl Iterator> + Clone { - self.polys.iter().map(move |poly| ProverQuery { - point: *x, - poly, - blind: Blind::default(), - }) + self.polys + .iter() + .map(move |poly| ProverQuery { point: *x, poly }) } pub(in crate::plonk) fn evaluate, T: TranscriptWrite>( @@ -289,12 +284,10 @@ impl Evaluated { .chain(Some(ProverQuery { point: *x, poly: &set.permutation_product_poly, - blind: set.permutation_product_blind, })) .chain(Some(ProverQuery { point: x_next, poly: &set.permutation_product_poly, - blind: set.permutation_product_blind, })) })) // Open it at \omega^{last} x for all but the last set. This rotation is only @@ -310,7 +303,6 @@ impl Evaluated { Some(ProverQuery { point: x_last, poly: &set.permutation_product_poly, - blind: set.permutation_product_blind, }) }), ) diff --git a/halo2_backend/src/plonk/prover.rs b/halo2_backend/src/plonk/prover.rs index 0285bd1ddd..08538d81df 100644 --- a/halo2_backend/src/plonk/prover.rs +++ b/halo2_backend/src/plonk/prover.rs @@ -207,39 +207,14 @@ impl< return Err(Error::InstanceTooLarge); } for (poly, value) in poly.iter_mut().zip(values.iter()) { - if !P::QUERY_INSTANCE { - // Add to the transcript the instance polynomials lagrange value. - transcript.common_scalar(*value)?; - } + // Add to the transcript the instance polynomials lagrange value. + transcript.common_scalar(*value)?; *poly = *value; } Ok(poly) }) .collect::, _>>()?; - if P::QUERY_INSTANCE { - // Add to the transcript the commitments of the instance lagrange polynomials - - let instance_commitments_projective: Vec<_> = instance_values - .iter() - .map(|poly| { - params.commit_lagrange(&engine.msm_backend, poly, Blind::default()) - }) - .collect(); - let mut instance_commitments = - vec![Scheme::Curve::identity(); instance_commitments_projective.len()]; - ::CurveExt::batch_normalize( - &instance_commitments_projective, - &mut instance_commitments, - ); - let instance_commitments = instance_commitments; - drop(instance_commitments_projective); - - for commitment in &instance_commitments { - transcript.common_point(*commitment)?; - } - } - // Convert from evaluation to coefficient form. let instance_polys: Vec<_> = instance_values @@ -587,9 +562,6 @@ impl< let x_pow_n = x.pow([self.params.n()]); - // [TRANSCRIPT-16] - self.write_instance_evals(x)?; - // 10. Compute and hash advice evals for the circuit instance ------------------------------------ // [TRANSCRIPT-17] self.write_advice_evals(x, &advice)?; @@ -622,30 +594,15 @@ impl< let shuffles_evaluated = self.evaluate_shuffles(x, shuffles_committed)?; // 13. Generate all queries ([`ProverQuery`]) that needs to be sent to prover -------------------- - let instances = std::mem::take(&mut self.instances); - let queries = instances - // group the instance, advice, permutation, lookups and shuffles + // group the advice, permutation, lookups and shuffles + let queries = advice .iter() - .zip(advice.iter()) .zip(permutations_evaluated.iter()) .zip(lookups_evaluated.iter()) .zip(shuffles_evaluated.iter()) - .flat_map(|((((instance, advice), permutation), lookups), shuffles)| { + .flat_map(|(((advice, permutation), lookups), shuffles)| { // Build a (an iterator) over a set of ProverQueries for each instance, advice, permutatiom, lookup and shuffle iter::empty() - // Instances - .chain( - P::QUERY_INSTANCE - .then_some(self.pk.vk.cs.instance_queries.iter().map( - move |&(column, at)| ProverQuery { - point: self.pk.vk.domain.rotate_omega(*x, at), - poly: &instance.instance_polys[column.index], - blind: Blind::default(), - }, - )) - .into_iter() - .flatten(), - ) // Advices .chain( self.pk @@ -656,7 +613,6 @@ impl< .map(move |&(column, at)| ProverQuery { point: self.pk.vk.domain.rotate_omega(*x, at), poly: &advice.advice_polys[column.index], - blind: advice.advice_blinds[column.index], }), ) // Permutations @@ -676,7 +632,7 @@ impl< .map(|&(column, at)| ProverQuery { point: self.pk.vk.domain.rotate_omega(*x, at), poly: &self.pk.fixed_polys[column.index], - blind: Blind::default(), + // blind: Blind::default(), }), ) // Copy constraints @@ -909,37 +865,6 @@ impl< Ok(vanishing) } - fn write_instance_evals(&mut self, x: ChallengeX) -> Result<(), Error> - where - Scheme::Scalar: WithSmallOrderMulGroup<3> + FromUniformBytes<64>, - { - if P::QUERY_INSTANCE { - // Compute and hash instance evals for the circuit instance - for instance in self.instances.iter() { - // Evaluate polynomials at omega^i x - let instance_evals: Vec<_> = self - .pk - .vk - .cs - .instance_queries - .iter() - .map(|&(column, at)| { - eval_polynomial( - &instance.instance_polys[column.index], - self.pk.vk.domain.rotate_omega(*x, at), - ) - }) - .collect(); - - // Hash each instance column evaluation - for eval in instance_evals.iter() { - self.transcript.write_scalar(*eval)?; - } - } - } - Ok(()) - } - fn write_advice_evals( &mut self, x: ChallengeX, diff --git a/halo2_backend/src/plonk/shuffle/prover.rs b/halo2_backend/src/plonk/shuffle/prover.rs index cc01a65255..b940f164a7 100644 --- a/halo2_backend/src/plonk/shuffle/prover.rs +++ b/halo2_backend/src/plonk/shuffle/prover.rs @@ -29,7 +29,6 @@ struct Compressed { #[derive(Debug)] pub(in crate::plonk) struct Committed { pub(in crate::plonk) product_poly: Polynomial, - product_blind: Blind, } pub(in crate::plonk) struct Evaluated { @@ -198,10 +197,7 @@ where // Hash product commitment transcript.write_point(product_commitment)?; - Ok(Committed:: { - product_poly: z, - product_blind, - }) + Ok(Committed:: { product_poly: z }) } impl Committed { @@ -242,13 +238,11 @@ impl Evaluated { .chain(Some(ProverQuery { point: *x, poly: &self.constructed.product_poly, - blind: self.constructed.product_blind, })) // Open shuffle product commitments at x_next .chain(Some(ProverQuery { point: x_next, poly: &self.constructed.product_poly, - blind: self.constructed.product_blind, })) } } diff --git a/halo2_backend/src/plonk/vanishing/prover.rs b/halo2_backend/src/plonk/vanishing/prover.rs index da56db9565..11b034bbda 100644 --- a/halo2_backend/src/plonk/vanishing/prover.rs +++ b/halo2_backend/src/plonk/vanishing/prover.rs @@ -21,18 +21,15 @@ use crate::{ pub(in crate::plonk) struct Committed { random_poly: Polynomial, - random_blind: Blind, } pub(in crate::plonk) struct Constructed { h_pieces: Vec>, - h_blinds: Vec>, committed: Committed, } pub(in crate::plonk) struct Evaluated { h_poly: Polynomial, - h_blind: Blind, committed: Committed, } @@ -90,10 +87,7 @@ impl Argument { .to_affine(); transcript.write_point(c)?; - Ok(Committed { - random_poly, - random_blind, - }) + Ok(Committed { random_poly }) } } @@ -154,7 +148,6 @@ impl Committed { Ok(Constructed { h_pieces, - h_blinds, committed: self, }) } @@ -174,18 +167,11 @@ impl Constructed { .rev() .fold(domain.empty_coeff(), |acc, eval| acc * xn + eval); - let h_blind = self - .h_blinds - .iter() - .rev() - .fold(Blind(C::Scalar::ZERO), |acc, eval| acc * Blind(xn) + *eval); - let random_eval = eval_polynomial(&self.committed.random_poly, *x); transcript.write_scalar(random_eval)?; Ok(Evaluated { h_poly, - h_blind, committed: self.committed, }) } @@ -200,12 +186,10 @@ impl Evaluated { .chain(Some(ProverQuery { point: *x, poly: &self.h_poly, - blind: self.h_blind, })) .chain(Some(ProverQuery { point: *x, poly: &self.committed.random_poly, - blind: self.committed.random_blind, })) } } diff --git a/halo2_backend/src/plonk/verifier.rs b/halo2_backend/src/plonk/verifier.rs index 45fc1c0a0e..3e62576fc7 100644 --- a/halo2_backend/src/plonk/verifier.rs +++ b/halo2_backend/src/plonk/verifier.rs @@ -1,11 +1,7 @@ //! Verify a plonk proof -use group::prime::PrimeCurveAffine; -use group::Curve; use halo2_middleware::circuit::Any; use halo2_middleware::ff::{Field, FromUniformBytes, WithSmallOrderMulGroup}; -use halo2_middleware::zal::impls::H2cEngine; -use halo2curves::CurveAffine; use std::iter; use super::{vanishing, VerifyingKey}; @@ -16,18 +12,12 @@ use crate::plonk::{ shuffle::verifier::shuffle_read_product_commitment, ChallengeBeta, ChallengeGamma, ChallengeTheta, ChallengeX, ChallengeY, Error, }; -use crate::poly::commitment::ParamsVerifier; use crate::poly::{ - commitment::{Blind, CommitmentScheme, Params, Verifier}, + commitment::{CommitmentScheme, Params, Verifier}, VerificationStrategy, VerifierQuery, }; use crate::transcript::{read_n_scalars, EncodedChallenge, TranscriptRead}; -#[cfg(feature = "batch")] -mod batch; -#[cfg(feature = "batch")] -pub use batch::BatchVerifier; - /// Returns a boolean indicating whether or not the proof is valid. Verifies a single proof (not /// batched). pub fn verify_proof<'params, Scheme, V, E, T, Strategy>( @@ -65,9 +55,6 @@ pub fn verify_proof_with_strategy< where Scheme::Scalar: WithSmallOrderMulGroup<3> + FromUniformBytes<64>, { - // ZAL: Verification is (supposedly) cheap, hence we don't use an accelerator engine - let default_engine = H2cEngine::new(); - // Check that instances matches the expected number of instance columns for instances in instances.iter() { if instances.len() != vk.cs.num_instance_columns { @@ -75,52 +62,7 @@ where } } - // Check that the Scheme parameters support commitment to instance - // if it is required by the verifier. - assert!( - !V::QUERY_INSTANCE - || >::COMMIT_INSTANCE - ); - - // 1. Get the commitments of the instance polynomials. ---------------------------------------- - - let instance_commitments = if V::QUERY_INSTANCE { - let mut instance_commitments = Vec::with_capacity(instances.len()); - - let instances_projective = instances - .iter() - .map(|instance| { - instance - .iter() - .map(|instance| { - if instance.len() > params.n() as usize - (vk.cs.blinding_factors() + 1) { - return Err(Error::InstanceTooLarge); - } - let mut poly = instance.to_vec(); - poly.resize(params.n() as usize, Scheme::Scalar::ZERO); - let poly = vk.domain.lagrange_from_vec(poly); - - Ok(params.commit_lagrange(&default_engine, &poly, Blind::default())) - }) - .collect::, _>>() - }) - .collect::, _>>()?; - - for instance_projective in instances_projective { - let mut affines = - vec![::Curve::identity(); instance_projective.len()]; - <::Curve as CurveAffine>::CurveExt::batch_normalize( - &instance_projective, - &mut affines, - ); - instance_commitments.push(affines); - } - instance_commitments - } else { - vec![vec![]; instances.len()] - }; - - let num_proofs = instance_commitments.len(); + let num_proofs = instances.len(); // 2. Add hash of verification key and instances into transcript. ----------------------------- // [TRANSCRIPT-1] @@ -130,19 +72,10 @@ where // 3. Add instance commitments into the transcript. -------------------------------------------- // [TRANSCRIPT-2] - if V::QUERY_INSTANCE { - for instance_commitments in instance_commitments.iter() { - // Hash the instance (external) commitments into the transcript - for commitment in instance_commitments { - transcript.common_point(*commitment)? - } - } - } else { - for instance in instances.iter() { - for instance in instance.iter() { - for value in instance.iter() { - transcript.common_scalar(*value)?; - } + for instance in instances.iter() { + for instance in instance.iter() { + for value in instance.iter() { + transcript.common_scalar(*value)?; } } } @@ -261,14 +194,7 @@ where let x: ChallengeX<_> = transcript.squeeze_challenge_scalar(); // 12. Get the instance evaluations - let instance_evals = if V::QUERY_INSTANCE { - // [TRANSCRIPT-16] - (0..num_proofs) - .map(|_| -> Result, _> { - read_n_scalars(transcript, vk.cs.instance_queries.len()) - }) - .collect::, _>>()? - } else { + let instance_evals = { let xn = x.pow([params.n()]); let (min_rotation, max_rotation) = vk.cs @@ -454,30 +380,14 @@ where }; #[rustfmt::skip] - let queries = instance_commitments - .iter() - .zip(instance_evals.iter()) - .zip(advice_commitments.iter()) + let queries = + advice_commitments.iter() .zip(advice_evals.iter()) .zip(permutations_evaluated.iter()) .zip(lookups_evaluated.iter()) .zip(shuffles_evaluated.iter()) - .flat_map(|((((((instance_commitments, instance_evals), advice_commitments),advice_evals),permutation),lookups),shuffles)| { + .flat_map(|((((advice_commitments,advice_evals),permutation),lookups),shuffles)| { iter::empty() - .chain( - V::QUERY_INSTANCE - .then_some(vk.cs.instance_queries.iter().enumerate().map( - move |(query_index, &(column, at))| { - VerifierQuery::new_commitment( - &instance_commitments[column.index], - vk.domain.rotate_omega(*x, at), - instance_evals[query_index], - ) - }, - )) - .into_iter() - .flatten(), - ) .chain(vk.cs.advice_queries.iter().enumerate().map( move |(query_index, &(column, at))| { VerifierQuery::new_commitment( diff --git a/halo2_backend/src/plonk/verifier/batch.rs b/halo2_backend/src/plonk/verifier/batch.rs deleted file mode 100644 index c849f2f23a..0000000000 --- a/halo2_backend/src/plonk/verifier/batch.rs +++ /dev/null @@ -1,131 +0,0 @@ -use crate::{plonk::Error, poly::commitment::ParamsVerifier}; -use group::ff::Field; -use halo2_middleware::ff::FromUniformBytes; -use halo2_middleware::zal::impls::H2cEngine; -use halo2curves::CurveAffine; -use rand_core::OsRng; - -use super::{verify_proof_with_strategy, VerificationStrategy}; -use crate::{ - multicore::{ - IndexedParallelIterator, IntoParallelIterator, ParallelIterator, TryFoldAndReduce, - }, - plonk::VerifyingKey, - poly::{ - commitment::MSM, - ipa::{ - commitment::{IPACommitmentScheme, ParamsVerifierIPA}, - msm::MSMIPA, - multiopen::VerifierIPA, - strategy::GuardIPA, - }, - }, - transcript::{Blake2bRead, TranscriptReadBuffer}, -}; - -/// A proof verification strategy that returns the proof's MSM. -/// -/// `BatchVerifier` handles the accumulation of the MSMs for the batched proofs. -#[derive(Debug)] -struct BatchStrategy<'params, C: CurveAffine> { - msm: MSMIPA<'params, C>, -} - -impl<'params, C: CurveAffine> VerificationStrategy<'params, IPACommitmentScheme, VerifierIPA> - for BatchStrategy<'params, C> -{ - fn new(params: &'params ParamsVerifierIPA) -> Self { - BatchStrategy { - msm: MSMIPA::new(params), - } - } - - fn process( - self, - f: impl FnOnce(MSMIPA<'params, C>) -> Result, Error>, - ) -> Result { - let guard = f(self.msm)?; - Ok(Self { - msm: guard.use_challenges(), - }) - } - - fn finalize(self) -> bool { - unreachable!() - } -} - -#[derive(Debug)] -struct BatchItem { - instances: Vec>>, - proof: Vec, -} - -/// A verifier that checks multiple proofs in a batch. **This requires the -/// `batch` crate feature to be enabled.** -#[derive(Debug, Default)] -pub struct BatchVerifier { - items: Vec>, -} - -impl BatchVerifier -where - C::Scalar: FromUniformBytes<64>, -{ - /// Constructs a new batch verifier. - pub fn new() -> Self { - Self { items: vec![] } - } - - /// Adds a proof to the batch. - pub fn add_proof(&mut self, instances: Vec>>, proof: Vec) { - self.items.push(BatchItem { instances, proof }) - } - - /// 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. - /// - /// 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: &ParamsVerifierIPA, vk: &VerifyingKey) -> bool { - fn accumulate_msm<'params, C: CurveAffine>( - 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. - acc.scale(C::Scalar::random(OsRng)); - acc.add_msm(&msm); - acc - } - - let final_msm = self - .items - .into_par_iter() - .enumerate() - .map(|(i, item)| { - let strategy = BatchStrategy::new(params); - let mut transcript = Blake2bRead::init(&item.proof[..]); - verify_proof_with_strategy(params, vk, strategy, &item.instances, &mut transcript) - .map_err(|e| { - tracing::debug!("Batch item {} failed verification: {}", i, e); - e - }) - .map(|st| st.msm) - }) - .try_fold_and_reduce( - || ParamsVerifier::<'_, C>::empty_msm(params), - |acc, res| res.map(|proof_msm| accumulate_msm(acc, proof_msm)), - ); - - match final_msm { - // ZAL: Verification is (supposedly) cheap, hence we don't use an accelerator engine - Ok(msm) => msm.check(&H2cEngine::new()), - Err(_) => false, - } - } -} diff --git a/halo2_backend/src/poly.rs b/halo2_backend/src/poly.rs index 093034ed83..a78d043c9b 100644 --- a/halo2_backend/src/poly.rs +++ b/halo2_backend/src/poly.rs @@ -18,9 +18,6 @@ mod domain; mod query; mod strategy; -/// Inner product argument commitment scheme -pub mod ipa; - /// KZG commitment scheme pub mod kzg; diff --git a/halo2_backend/src/poly/commitment.rs b/halo2_backend/src/poly/commitment.rs index fb11099150..db0b40490b 100644 --- a/halo2_backend/src/poly/commitment.rs +++ b/halo2_backend/src/poly/commitment.rs @@ -121,9 +121,6 @@ pub trait MSM: Clone + Debug + Send + Sync { /// Common multi-open prover interface for various commitment schemes pub trait Prover<'params, Scheme: CommitmentScheme> { - /// Query instance or not - const QUERY_INSTANCE: bool; - /// Creates new prover instance fn new(params: &'params Scheme::ParamsProver) -> Self; @@ -176,9 +173,6 @@ pub trait Verifier<'params, Scheme: CommitmentScheme> { /// Accumulator for compressed verification type MSMAccumulator; - /// Query instance or not - const QUERY_INSTANCE: bool; - /// Creates new verifier instance fn new() -> Self; diff --git a/halo2_backend/src/poly/ipa/commitment.rs b/halo2_backend/src/poly/ipa/commitment.rs deleted file mode 100644 index e1436e28c5..0000000000 --- a/halo2_backend/src/poly/ipa/commitment.rs +++ /dev/null @@ -1,386 +0,0 @@ -//! This module contains an implementation of the polynomial commitment scheme -//! described in the [Halo][halo] paper. -//! -//! [halo]: https://eprint.iacr.org/2019/1021 - -use crate::arithmetic::{g_to_lagrange, parallelize, CurveAffine, CurveExt}; -use crate::helpers::CurveRead; -use crate::poly::commitment::{Blind, CommitmentScheme, Params, ParamsProver, ParamsVerifier}; -use crate::poly::ipa::msm::MSMIPA; -use crate::poly::{Coeff, LagrangeCoeff, Polynomial}; - -use group::{Curve, Group}; -use halo2_middleware::zal::traits::MsmAccel; -use std::marker::PhantomData; - -mod prover; -mod verifier; - -pub use prover::create_proof_with_engine; -pub use verifier::verify_proof; - -use std::io; - -/// Public parameters for IPA commitment scheme -#[derive(Debug, Clone)] -pub struct ParamsIPA { - pub(crate) k: u32, - pub(crate) n: u64, - pub(crate) g: Vec, - pub(crate) g_lagrange: Vec, - pub(crate) w: C, - pub(crate) u: C, -} - -/// Concrete IPA commitment scheme -#[derive(Debug)] -pub struct IPACommitmentScheme { - _marker: PhantomData, -} - -impl CommitmentScheme for IPACommitmentScheme { - type Scalar = C::ScalarExt; - type Curve = C; - - type ParamsProver = ParamsIPA; - type ParamsVerifier = ParamsVerifierIPA; - - fn new_params(k: u32) -> Self::ParamsProver { - ParamsIPA::new(k) - } - - fn read_params(reader: &mut R) -> io::Result { - ParamsIPA::read(reader) - } -} - -/// Verifier parameters -pub type ParamsVerifierIPA = ParamsIPA; - -impl<'params, C: CurveAffine> ParamsVerifier<'params, C> for ParamsIPA { - type MSM = MSMIPA<'params, C>; - - // IPA params always support commitment. - const COMMIT_INSTANCE: bool = true; - - fn empty_msm(&self) -> MSMIPA { - MSMIPA::new(self) - } -} - -impl Params for ParamsIPA { - fn k(&self) -> u32 { - self.k - } - - fn n(&self) -> u64 { - self.n - } - - fn downsize(&mut self, k: u32) { - assert!(k <= self.k); - - self.k = k; - self.n = 1 << k; - self.g.truncate(self.n as usize); - self.g_lagrange = g_to_lagrange(self.g.iter().map(|g| g.to_curve()).collect(), k); - } - - /// This commits to a polynomial using its evaluations over the $2^k$ size - /// evaluation domain. The commitment will be blinded by the blinding factor - /// `r`. - fn commit_lagrange( - &self, - engine: &impl MsmAccel, - poly: &Polynomial, - r: Blind, - ) -> C::Curve { - let mut tmp_scalars = Vec::with_capacity(poly.len() + 1); - let mut tmp_bases = Vec::with_capacity(poly.len() + 1); - - tmp_scalars.extend(poly.iter()); - tmp_scalars.push(r.0); - - tmp_bases.extend(self.g_lagrange.iter()); - tmp_bases.push(self.w); - - engine.msm(&tmp_scalars, &tmp_bases) - } - - /// Writes params to a buffer. - fn write(&self, writer: &mut W) -> io::Result<()> { - writer.write_all(&self.k.to_le_bytes())?; - for g_element in &self.g { - writer.write_all(g_element.to_bytes().as_ref())?; - } - for g_lagrange_element in &self.g_lagrange { - writer.write_all(g_lagrange_element.to_bytes().as_ref())?; - } - writer.write_all(self.w.to_bytes().as_ref())?; - writer.write_all(self.u.to_bytes().as_ref())?; - - Ok(()) - } - - /// Reads params from a buffer. - fn read(reader: &mut R) -> io::Result { - let mut k = [0u8; 4]; - reader.read_exact(&mut k[..])?; - let k = u32::from_le_bytes(k); - - let n: u64 = 1 << k; - - let g: Vec<_> = (0..n).map(|_| C::read(reader)).collect::>()?; - let g_lagrange: Vec<_> = (0..n).map(|_| C::read(reader)).collect::>()?; - - let w = C::read(reader)?; - let u = C::read(reader)?; - - Ok(Self { - k, - n, - g, - g_lagrange, - w, - u, - }) - } -} - -impl ParamsProver for ParamsIPA { - /// Initializes parameters for the curve, given a random oracle to draw - /// points from. - fn new(k: u32) -> Self { - // This is usually a limitation on the curve, but we also want 32-bit - // architectures to be supported. - assert!(k < 32); - - // In src/arithmetic/fields.rs we ensure that usize is at least 32 bits. - - let n: u64 = 1 << k; - - let g_projective = { - let mut g = Vec::with_capacity(n as usize); - g.resize(n as usize, C::Curve::identity()); - - parallelize(&mut g, move |g, start| { - let hasher = C::CurveExt::hash_to_curve("Halo2-Parameters"); - - for (i, g) in g.iter_mut().enumerate() { - let i = (i + start) as u32; - - let mut message = [0u8; 5]; - message[1..5].copy_from_slice(&i.to_le_bytes()); - - *g = hasher(&message); - } - }); - - g - }; - - let g = { - let mut g = vec![C::identity(); n as usize]; - parallelize(&mut g, |g, starts| { - C::Curve::batch_normalize(&g_projective[starts..(starts + g.len())], g); - }); - g - }; - - // Let's evaluate all of the Lagrange basis polynomials - // using an inverse FFT. - let g_lagrange = g_to_lagrange(g_projective, k); - - let hasher = C::CurveExt::hash_to_curve("Halo2-Parameters"); - - let [w, u] = { - let projectives = vec![hasher(&[1]), hasher(&[2])]; - let mut affines = [C::identity(); 2]; - C::CurveExt::batch_normalize(&projectives, &mut affines); - affines - }; - - ParamsIPA { - k, - n, - g, - g_lagrange, - w, - u, - } - } - - /// This computes a commitment to a polynomial described by the provided - /// slice of coefficients. The commitment will be blinded by the blinding - /// factor `r`. - fn commit( - &self, - engine: &impl MsmAccel, - poly: &Polynomial, - r: Blind, - ) -> C::Curve { - let mut tmp_scalars = Vec::with_capacity(poly.len() + 1); - let mut tmp_bases = Vec::with_capacity(poly.len() + 1); - - tmp_scalars.extend(poly.iter()); - tmp_scalars.push(r.0); - - tmp_bases.extend(self.g.iter()); - tmp_bases.push(self.w); - - engine.msm(&tmp_scalars, &tmp_bases) - } -} - -#[cfg(test)] -mod test { - use crate::poly::commitment::ParamsProver; - use crate::poly::commitment::{Blind, Params, MSM}; - use crate::poly::ipa::commitment::{create_proof_with_engine, verify_proof, ParamsIPA}; - use crate::poly::ipa::msm::MSMIPA; - - use group::Curve; - use halo2_middleware::ff::Field; - use halo2_middleware::zal::impls::H2cEngine; - - #[test] - fn test_commit_lagrange_epaffine() { - const K: u32 = 6; - - use rand_core::OsRng; - - use crate::poly::EvaluationDomain; - use halo2curves::pasta::{EpAffine, Fq}; - - let engine = H2cEngine::new(); - let params = ParamsIPA::::new(K); - let domain = EvaluationDomain::new(1, K); - - let mut a = domain.empty_lagrange(); - - for (i, a) in a.iter_mut().enumerate() { - *a = Fq::from(i as u64); - } - - let b = domain.lagrange_to_coeff(a.clone()); - - let alpha = Blind(Fq::random(OsRng)); - - assert_eq!( - params.commit(&engine, &b, alpha), - params.commit_lagrange(&engine, &a, alpha) - ); - } - - #[test] - fn test_commit_lagrange_eqaffine() { - const K: u32 = 6; - - use rand_core::OsRng; - - use crate::poly::EvaluationDomain; - use halo2curves::pasta::{EqAffine, Fp}; - - let engine = H2cEngine::new(); - let params: ParamsIPA = ParamsIPA::::new(K); - let domain = EvaluationDomain::new(1, K); - - let mut a = domain.empty_lagrange(); - - for (i, a) in a.iter_mut().enumerate() { - *a = Fp::from(i as u64); - } - - let b = domain.lagrange_to_coeff(a.clone()); - - let alpha = Blind(Fp::random(OsRng)); - - assert_eq!( - params.commit(&engine, &b, alpha), - params.commit_lagrange(&engine, &a, alpha) - ); - } - - #[test] - fn test_opening_proof() { - const K: u32 = 6; - - use halo2_middleware::ff::Field; - use rand_core::OsRng; - - use super::super::commitment::{Blind, Params}; - use crate::arithmetic::eval_polynomial; - use crate::poly::EvaluationDomain; - use crate::transcript::{ - Blake2bRead, Blake2bWrite, Challenge255, Transcript, TranscriptRead, TranscriptWrite, - }; - use halo2curves::pasta::{EpAffine, Fq}; - - use crate::transcript::TranscriptReadBuffer; - use crate::transcript::TranscriptWriterBuffer; - - let rng = OsRng; - - let engine = H2cEngine::new(); - let params = ParamsIPA::::new(K); - let mut params_buffer = vec![]; - as Params<_>>::write(¶ms, &mut params_buffer).unwrap(); - let params: ParamsIPA = Params::read::<_>(&mut ¶ms_buffer[..]).unwrap(); - - let domain = EvaluationDomain::new(1, K); - - let mut px = domain.empty_coeff(); - - for (i, a) in px.iter_mut().enumerate() { - *a = Fq::from(i as u64); - } - - let blind = Blind(Fq::random(rng)); - - let p = params.commit(&engine, &px, blind).to_affine(); - - let mut transcript = - Blake2bWrite::, EpAffine, Challenge255>::init(vec![]); - transcript.write_point(p).unwrap(); - let x = transcript.squeeze_challenge_scalar::<()>(); - // Evaluate the polynomial - let v = eval_polynomial(&px, *x); - transcript.write_scalar(v).unwrap(); - - let (proof, ch_prover) = { - create_proof_with_engine(&engine, ¶ms, rng, &mut transcript, &px, blind, *x) - .unwrap(); - let ch_prover = transcript.squeeze_challenge(); - (transcript.finalize(), ch_prover) - }; - - // Verify the opening proof - let mut transcript = - Blake2bRead::<&[u8], EpAffine, Challenge255>::init(&proof[..]); - let p_prime = transcript.read_point().unwrap(); - assert_eq!(p, p_prime); - let x_prime = transcript.squeeze_challenge_scalar::<()>(); - assert_eq!(*x, *x_prime); - let v_prime = transcript.read_scalar().unwrap(); - assert_eq!(v, v_prime); - - let mut commitment_msm = MSMIPA::new(¶ms); - commitment_msm.append_term(Fq::one(), p.into()); - - let guard = verify_proof(commitment_msm, &mut transcript, *x, v).unwrap(); - let ch_verifier = transcript.squeeze_challenge(); - assert_eq!(*ch_prover, *ch_verifier); - - // Test guard behavior prior to checking another proof - { - // Test use_challenges() - let msm_challenges = guard.clone().use_challenges(); - assert!(msm_challenges.check(&engine)); - - // Test use_g() - let g = guard.compute_g(&engine); - let (msm_g, _accumulator) = guard.clone().use_g(g); - assert!(msm_g.check(&engine)); - } - } -} diff --git a/halo2_backend/src/poly/ipa/commitment/prover.rs b/halo2_backend/src/poly/ipa/commitment/prover.rs deleted file mode 100644 index 7e04206e07..0000000000 --- a/halo2_backend/src/poly/ipa/commitment/prover.rs +++ /dev/null @@ -1,170 +0,0 @@ -use halo2_middleware::ff::Field; -use halo2_middleware::zal::traits::MsmAccel; -use rand_core::RngCore; - -use super::ParamsIPA; -use crate::arithmetic::{compute_inner_product, eval_polynomial, parallelize, CurveAffine}; - -use crate::poly::commitment::ParamsProver; -use crate::poly::{commitment::Blind, Coeff, Polynomial}; -use crate::transcript::{EncodedChallenge, TranscriptWrite}; - -use group::Curve; -use std::io::{self}; - -/// Create a polynomial commitment opening proof for the polynomial defined -/// by the coefficients `px`, the blinding factor `blind` used for the -/// polynomial commitment, and the point `x` that the polynomial is -/// evaluated at. -/// -/// This function will panic if the provided polynomial is too large with -/// respect to the polynomial commitment parameters. -/// -/// **Important:** This function assumes that the provided `transcript` has -/// already seen the common inputs: the polynomial commitment P, the claimed -/// opening v, and the point x. It's probably also nice for the transcript -/// to have seen the elliptic curve description and the URS, if you want to -/// be rigorous. -pub fn create_proof_with_engine< - C: CurveAffine, - E: EncodedChallenge, - R: RngCore, - T: TranscriptWrite, ->( - engine: &impl MsmAccel, - params: &ParamsIPA, - mut rng: R, - transcript: &mut T, - p_poly: &Polynomial, - p_blind: Blind, - x_3: C::Scalar, -) -> io::Result<()> { - // We're limited to polynomials of degree n - 1. - assert_eq!(p_poly.len(), params.n as usize); - - // Sample a random polynomial (of same degree) that has a root at x_3, first - // by setting all coefficients to random values. - let mut s_poly = (*p_poly).clone(); - for coeff in s_poly.iter_mut() { - *coeff = C::Scalar::random(&mut rng); - } - // Evaluate the random polynomial at x_3 - let s_at_x3 = eval_polynomial(&s_poly[..], x_3); - // Subtract constant coefficient to get a random polynomial with a root at x_3 - s_poly[0] -= &s_at_x3; - // And sample a random blind - let s_poly_blind = Blind(C::Scalar::random(&mut rng)); - - // Write a commitment to the random polynomial to the transcript - let s_poly_commitment = params.commit(engine, &s_poly, s_poly_blind).to_affine(); - transcript.write_point(s_poly_commitment)?; - - // Challenge that will ensure that the prover cannot change P but can only - // witness a random polynomial commitment that agrees with P at x_3, with high - // probability. - let xi = *transcript.squeeze_challenge_scalar::<()>(); - - // Challenge that ensures that the prover did not interfere with the U term - // in their commitments. - let z = *transcript.squeeze_challenge_scalar::<()>(); - - // We'll be opening `P' = P - [v] G_0 + [ξ] S` to ensure it has a root at - // zero. - let mut p_prime_poly = s_poly * xi + p_poly; - let v = eval_polynomial(&p_prime_poly, x_3); - p_prime_poly[0] -= &v; - let p_prime_blind = s_poly_blind * Blind(xi) + p_blind; - - // This accumulates the synthetic blinding factor `f` starting - // with the blinding factor for `P'`. - let mut f = p_prime_blind.0; - - // Initialize the vector `p_prime` as the coefficients of the polynomial. - let mut p_prime = p_prime_poly.values; - assert_eq!(p_prime.len(), params.n as usize); - - // Initialize the vector `b` as the powers of `x_3`. The inner product of - // `p_prime` and `b` is the evaluation of the polynomial at `x_3`. - let mut b = Vec::with_capacity(1 << params.k); - { - let mut cur = C::Scalar::ONE; - for _ in 0..(1 << params.k) { - b.push(cur); - cur *= &x_3; - } - } - - // Initialize the vector `G'` from the URS. We'll be progressively collapsing - // this vector into smaller and smaller vectors until it is of length 1. - let mut g_prime = params.g.clone(); - - // Perform the inner product argument, round by round. - for j in 0..params.k { - let half = 1 << (params.k - j - 1); // half the length of `p_prime`, `b`, `G'` - - // Compute L, R - // - // TODO: If we modify multiexp to take "extra" bases, we could speed - // this piece up a bit by combining the multiexps. - let l_j = engine.msm(&p_prime[half..], &g_prime[0..half]); - let r_j = engine.msm(&p_prime[0..half], &g_prime[half..]); - let value_l_j = compute_inner_product(&p_prime[half..], &b[0..half]); - let value_r_j = compute_inner_product(&p_prime[0..half], &b[half..]); - let l_j_randomness = C::Scalar::random(&mut rng); - let r_j_randomness = C::Scalar::random(&mut rng); - let l_j = l_j + engine.msm(&[value_l_j * z, l_j_randomness], &[params.u, params.w]); - let r_j = r_j + engine.msm(&[value_r_j * z, r_j_randomness], &[params.u, params.w]); - let [l_j, r_j] = { - let mut affines = [C::identity(); 2]; - C::CurveExt::batch_normalize(&[l_j, r_j], &mut affines); - affines - }; - - // Feed L and R into the real transcript - transcript.write_point(l_j)?; - transcript.write_point(r_j)?; - - let u_j = *transcript.squeeze_challenge_scalar::<()>(); - let u_j_inv = u_j.invert().unwrap(); // TODO, bubble this up - - // Collapse `p_prime` and `b`. - // TODO: parallelize - for i in 0..half { - p_prime[i] = p_prime[i] + (p_prime[i + half] * u_j_inv); - b[i] = b[i] + (b[i + half] * u_j); - } - p_prime.truncate(half); - b.truncate(half); - - // Collapse `G'` - parallel_generator_collapse(&mut g_prime, u_j); - g_prime.truncate(half); - - // Update randomness (the synthetic blinding factor at the end) - f += l_j_randomness * u_j_inv; - f += r_j_randomness * u_j; - } - - // We have fully collapsed `p_prime`, `b`, `G'` - assert_eq!(p_prime.len(), 1); - let c = p_prime[0]; - - transcript.write_scalar(c)?; - transcript.write_scalar(f)?; - - Ok(()) -} - -fn parallel_generator_collapse(g: &mut [C], challenge: C::Scalar) { - let len = g.len() / 2; - let (g_lo, g_hi) = g.split_at_mut(len); - - parallelize(g_lo, |g_lo, start| { - let g_hi = &g_hi[start..]; - let mut tmp = Vec::with_capacity(g_lo.len()); - for (g_lo, g_hi) in g_lo.iter().zip(g_hi.iter()) { - tmp.push(g_lo.to_curve() + *g_hi * challenge); - } - C::Curve::batch_normalize(&tmp, g_lo); - }); -} diff --git a/halo2_backend/src/poly/ipa/commitment/verifier.rs b/halo2_backend/src/poly/ipa/commitment/verifier.rs deleted file mode 100644 index 2e6723c5b6..0000000000 --- a/halo2_backend/src/poly/ipa/commitment/verifier.rs +++ /dev/null @@ -1,98 +0,0 @@ -use group::ff::{BatchInvert, Field}; - -use crate::{arithmetic::CurveAffine, poly::ipa::strategy::GuardIPA}; -use crate::{ - poly::{commitment::MSM, ipa::msm::MSMIPA, Error}, - transcript::{EncodedChallenge, TranscriptRead}, -}; - -/// Checks to see if the proof represented within `transcript` is valid, and a -/// point `x` that the polynomial commitment `P` opens purportedly to the value -/// `v`. The provided `msm` should evaluate to the commitment `P` being opened. -pub fn verify_proof<'params, C: CurveAffine, E: EncodedChallenge, T: TranscriptRead>( - mut msm: MSMIPA<'params, C>, - transcript: &mut T, - x: C::Scalar, - v: C::Scalar, -) -> Result, Error> { - let k = msm.params.k as usize; - - // P' = P - [v] G_0 + [ξ] S - msm.add_constant_term(-v); // add [-v] G_0 - let s_poly_commitment = transcript.read_point().map_err(|_| Error::OpeningError)?; - let xi = *transcript.squeeze_challenge_scalar::<()>(); - msm.append_term(xi, s_poly_commitment.into()); - - let z = *transcript.squeeze_challenge_scalar::<()>(); - - let mut rounds = vec![]; - for _ in 0..k { - // Read L and R from the proof and write them to the transcript - let l = transcript.read_point().map_err(|_| Error::OpeningError)?; - let r = transcript.read_point().map_err(|_| Error::OpeningError)?; - - let u_j_packed = transcript.squeeze_challenge(); - let u_j = *u_j_packed.as_challenge_scalar::<()>(); - - rounds.push((l, r, u_j, /* to be inverted */ u_j, u_j_packed)); - } - - rounds - .iter_mut() - .map(|&mut (_, _, _, ref mut u_j, _)| u_j) - .batch_invert(); - - // This is the left-hand side of the verifier equation. - // P' + \sum([u_j^{-1}] L_j) + \sum([u_j] R_j) - let mut u = Vec::with_capacity(k); - let mut u_packed: Vec = Vec::with_capacity(k); - for (l, r, u_j, u_j_inv, u_j_packed) in rounds { - msm.append_term(u_j_inv, l.into()); - msm.append_term(u_j, r.into()); - - u.push(u_j); - u_packed.push(u_j_packed.get_scalar()); - } - - // Our goal is to check that the left hand side of the verifier - // equation - // P' + \sum([u_j^{-1}] L_j) + \sum([u_j] R_j) - // equals (given b = \mathbf{b}_0, and the prover's values c, f), - // the right-hand side - // = [c] (G'_0 + [b * z] U) + [f] W - // Subtracting the right-hand side from both sides we get - // P' + \sum([u_j^{-1}] L_j) + \sum([u_j] R_j) - // + [-c] G'_0 + [-cbz] U + [-f] W - // = 0 - // - // Note that the guard returned from this function does not include - // the [-c]G'_0 term. - - let c = transcript.read_scalar().map_err(|_| Error::SamplingError)?; - let neg_c = -c; - let f = transcript.read_scalar().map_err(|_| Error::SamplingError)?; - let b = compute_b(x, &u); - - msm.add_to_u_scalar(neg_c * b * z); - msm.add_to_w_scalar(-f); - - let guard = GuardIPA { - msm, - neg_c, - u, - u_packed, - }; - - Ok(guard) -} - -/// Computes $\prod\limits_{i=0}^{k-1} (1 + u_{k - 1 - i} x^{2^i})$. -fn compute_b(x: F, u: &[F]) -> F { - let mut tmp = F::ONE; - let mut cur = x; - for u_j in u.iter().rev() { - tmp *= F::ONE + (*u_j * cur); - cur *= cur; - } - tmp -} diff --git a/halo2_backend/src/poly/ipa/mod.rs b/halo2_backend/src/poly/ipa/mod.rs deleted file mode 100644 index 3600e2f051..0000000000 --- a/halo2_backend/src/poly/ipa/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -pub mod commitment; -/// Multiscalar multiplication engines -pub mod msm; -/// IPA multi-open scheme -pub mod multiopen; -/// Strategies used with KZG scheme -pub mod strategy; diff --git a/halo2_backend/src/poly/ipa/msm.rs b/halo2_backend/src/poly/ipa/msm.rs deleted file mode 100644 index b2869e9dd0..0000000000 --- a/halo2_backend/src/poly/ipa/msm.rs +++ /dev/null @@ -1,273 +0,0 @@ -use crate::arithmetic::CurveAffine; -use crate::poly::{commitment::MSM, ipa::commitment::ParamsVerifierIPA}; -use group::Group; -use halo2_middleware::ff::Field; -use halo2_middleware::zal::traits::MsmAccel; -use std::collections::BTreeMap; - -/// A multiscalar multiplication in the polynomial commitment scheme -#[derive(Debug, Clone)] -pub struct MSMIPA<'params, C: CurveAffine> { - pub(crate) params: &'params ParamsVerifierIPA, - g_scalars: Option>, - w_scalar: Option, - u_scalar: Option, - // x-coordinate -> (scalar, y-coordinate) - other: BTreeMap, -} - -impl<'a, C: CurveAffine> MSMIPA<'a, C> { - /// Given verifier parameters Creates an empty multi scalar engine - pub fn new(params: &'a ParamsVerifierIPA) -> Self { - let g_scalars = None; - let w_scalar = None; - let u_scalar = None; - let other = BTreeMap::new(); - - Self { - g_scalars, - w_scalar, - u_scalar, - other, - - params, - } - } - - /// Add another multiexp into this one - pub fn add_msm(&mut self, other: &Self) { - 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); - } - } -} - -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(); - - 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)); - } - } - - /// Add another multiexp into this one - fn add_msm(&mut self, other: &Self) { - 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) { - if let Some(g_scalars) = &mut self.g_scalars { - for g_scalar in g_scalars { - *g_scalar *= &factor; - } - } - - for other in self.other.values_mut() { - other.0 *= factor; - } - - self.w_scalar = self.w_scalar.map(|a| a * factor); - self.u_scalar = self.u_scalar.map(|a| a * factor); - } - - fn check(&self, engine: &impl MsmAccel) -> bool { - bool::from(self.eval(engine).is_identity()) - } - - fn eval(&self, engine: &impl MsmAccel) -> C::Curve { - let len = self.g_scalars.as_ref().map(|v| v.len()).unwrap_or(0) - + self.w_scalar.map(|_| 1).unwrap_or(0) - + 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); - - scalars.extend(self.other.values().map(|(scalar, _)| scalar)); - bases.extend( - self.other - .iter() - .map(|(x, (_, y))| C::from_xy(*x, *y).unwrap()), - ); - - if let Some(w_scalar) = self.w_scalar { - scalars.push(w_scalar); - bases.push(self.params.w); - } - - if let Some(u_scalar) = self.u_scalar { - scalars.push(u_scalar); - bases.push(self.params.u); - } - - if let Some(g_scalars) = &self.g_scalars { - scalars.extend(g_scalars); - bases.extend(self.params.g.iter()); - } - - assert_eq!(scalars.len(), len); - engine.msm(&scalars, &bases) - } - - fn bases(&self) -> Vec { - self.other - .iter() - .map(|(x, (_, y))| C::from_xy(*x, *y).unwrap().into()) - .collect() - } - - fn scalars(&self) -> Vec { - self.other.values().map(|(scalar, _)| *scalar).collect() - } -} - -impl<'a, C: CurveAffine> MSMIPA<'a, C> { - /// Add a value to the first entry of `g_scalars`. - pub fn add_constant_term(&mut self, constant: C::Scalar) { - if let Some(g_scalars) = self.g_scalars.as_mut() { - g_scalars[0] += &constant; - } else { - let mut g_scalars = vec![C::Scalar::ZERO; self.params.n as usize]; - g_scalars[0] += &constant; - self.g_scalars = Some(g_scalars); - } - } - - /// Add a vector of scalars to `g_scalars`. This function will panic if the - /// caller provides a slice of scalars that is not of length `params.n`. - pub fn add_to_g_scalars(&mut self, scalars: &[C::Scalar]) { - assert_eq!(scalars.len(), self.params.n as usize); - if let Some(g_scalars) = &mut self.g_scalars { - for (g_scalar, scalar) in g_scalars.iter_mut().zip(scalars.iter()) { - *g_scalar += scalar; - } - } else { - self.g_scalars = Some(scalars.to_vec()); - } - } - /// Add to `w_scalar` - pub fn add_to_w_scalar(&mut self, scalar: C::Scalar) { - self.w_scalar = self.w_scalar.map_or(Some(scalar), |a| Some(a + scalar)); - } - - /// Add to `u_scalar` - pub fn add_to_u_scalar(&mut self, scalar: C::Scalar) { - self.u_scalar = self.u_scalar.map_or(Some(scalar), |a| Some(a + scalar)); - } -} - -#[cfg(test)] -mod tests { - use crate::poly::{ - commitment::{ParamsProver, MSM}, - ipa::{commitment::ParamsIPA, msm::MSMIPA}, - }; - use halo2_middleware::zal::impls::H2cEngine; - use halo2curves::{ - pasta::{Ep, EpAffine, Fp, Fq}, - CurveAffine, - }; - - #[test] - fn msm_arithmetic() { - let base: Ep = EpAffine::from_xy(-Fp::one(), Fp::from(2)).unwrap().into(); - let base_viol = base + base; - - let engine = H2cEngine::new(); - let params = ParamsIPA::new(4); - let mut a: MSMIPA = MSMIPA::new(¶ms); - a.append_term(Fq::one(), base); - // a = [1] P - assert!(!a.clone().check(&engine)); - a.append_term(Fq::one(), base); - // a = [1+1] P - assert!(!a.clone().check(&engine)); - a.append_term(-Fq::one(), base_viol); - // a = [1+1] P + [-1] 2P - assert!(a.clone().check(&engine)); - 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().check(&engine)); - a.append_term(Fq::from(2), base_viol); - // a = [1+1-4] P + [-1+2] 2P - assert!(a.clone().check(&engine)); - - // 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().check(&engine)); - - 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().check(&engine)); - // Add two MSMs with bases that differ only in sign. - a.add_msm(&c); - assert!(a.check(&engine)); - } -} diff --git a/halo2_backend/src/poly/ipa/multiopen.rs b/halo2_backend/src/poly/ipa/multiopen.rs deleted file mode 100644 index d4e1a33ba1..0000000000 --- a/halo2_backend/src/poly/ipa/multiopen.rs +++ /dev/null @@ -1,172 +0,0 @@ -//! This module contains an optimisation of the polynomial commitment opening -//! scheme described in the [Halo][halo] paper. -//! -//! [halo]: https://eprint.iacr.org/2019/1021 - -use super::*; -use crate::{poly::query::Query, transcript::ChallengeScalar}; -use halo2_middleware::ff::Field; -use std::collections::{BTreeMap, BTreeSet}; - -mod prover; -mod verifier; - -pub use prover::ProverIPA; -pub use verifier::VerifierIPA; - -#[derive(Clone, Copy, Debug)] -struct X1 {} -/// Challenge for compressing openings at the same point sets together. -type ChallengeX1 = ChallengeScalar; - -#[derive(Clone, Copy, Debug)] -struct X2 {} -/// Challenge for keeping the multi-point quotient polynomial terms linearly independent. -type ChallengeX2 = ChallengeScalar; - -#[derive(Clone, Copy, Debug)] -struct X3 {} -/// Challenge point at which the commitments are opened. -type ChallengeX3 = ChallengeScalar; - -#[derive(Clone, Copy, Debug)] -struct X4 {} -/// Challenge for collapsing the openings of the various remaining polynomials at x_3 -/// together. -type ChallengeX4 = ChallengeScalar; - -#[derive(Debug)] -struct CommitmentData { - pub(crate) commitment: T, - pub(crate) set_index: usize, - pub(crate) point_indices: Vec, - pub(crate) evals: Vec, -} - -impl CommitmentData { - fn new(commitment: T) -> Self { - CommitmentData { - commitment, - set_index: 0, - point_indices: vec![], - evals: vec![], - } - } -} - -type IntermediateSets = ( - Vec>::Eval, >::Commitment>>, - Vec>, -); - -fn construct_intermediate_sets>(queries: I) -> IntermediateSets -where - I: IntoIterator + Clone, -{ - // Construct sets of unique commitments and corresponding information about - // their queries. - let mut commitment_map: Vec> = vec![]; - - // Also construct mapping from a unique point to a point_index. This defines - // an ordering on the points. - let mut point_index_map = BTreeMap::new(); - - // Iterate over all of the queries, computing the ordering of the points - // while also creating new commitment data. - for query in queries.clone() { - let num_points = point_index_map.len(); - let point_idx = point_index_map - .entry(query.get_point()) - .or_insert(num_points); - - if let Some(pos) = commitment_map - .iter() - .position(|comm| comm.commitment == query.get_commitment()) - { - commitment_map[pos].point_indices.push(*point_idx); - } else { - let mut tmp = CommitmentData::new(query.get_commitment()); - tmp.point_indices.push(*point_idx); - commitment_map.push(tmp); - } - } - - // Also construct inverse mapping from point_index to the point - let mut inverse_point_index_map = BTreeMap::new(); - for (&point, &point_index) in point_index_map.iter() { - inverse_point_index_map.insert(point_index, point); - } - - // Construct map of unique ordered point_idx_sets to their set_idx - let mut point_idx_sets = BTreeMap::new(); - // Also construct mapping from commitment to point_idx_set - let mut commitment_set_map = Vec::new(); - - for commitment_data in commitment_map.iter() { - let mut point_index_set = BTreeSet::new(); - // Note that point_index_set is ordered, unlike point_indices - for &point_index in commitment_data.point_indices.iter() { - point_index_set.insert(point_index); - } - - // Push point_index_set to CommitmentData for the relevant commitment - commitment_set_map.push((commitment_data.commitment, point_index_set.clone())); - - let num_sets = point_idx_sets.len(); - point_idx_sets.entry(point_index_set).or_insert(num_sets); - } - - // Initialise empty evals vec for each unique commitment - for commitment_data in commitment_map.iter_mut() { - let len = commitment_data.point_indices.len(); - commitment_data.evals = vec![Q::Eval::default(); len]; - } - - // Populate set_index, evals and points for each commitment using point_idx_sets - for query in queries { - // The index of the point at which the commitment is queried - let point_index = point_index_map.get(&query.get_point()).unwrap(); - - // The point_index_set at which the commitment was queried - let mut point_index_set = BTreeSet::new(); - for (commitment, point_idx_set) in commitment_set_map.iter() { - if query.get_commitment() == *commitment { - point_index_set.clone_from(point_idx_set); - } - } - assert!(!point_index_set.is_empty()); - - // The set_index of the point_index_set - let set_index = point_idx_sets.get(&point_index_set).unwrap(); - for commitment_data in commitment_map.iter_mut() { - if query.get_commitment() == commitment_data.commitment { - commitment_data.set_index = *set_index; - } - } - let point_index_set: Vec = point_index_set.iter().cloned().collect(); - - // The offset of the point_index in the point_index_set - let point_index_in_set = point_index_set - .iter() - .position(|i| i == point_index) - .unwrap(); - - for commitment_data in commitment_map.iter_mut() { - if query.get_commitment() == commitment_data.commitment { - // Insert the eval using the ordering of the point_index_set - commitment_data.evals[point_index_in_set] = query.get_eval(); - } - } - } - - // Get actual points in each point set - let mut point_sets: Vec> = vec![Vec::new(); point_idx_sets.len()]; - for (point_idx_set, &set_idx) in point_idx_sets.iter() { - for &point_idx in point_idx_set.iter() { - let point = inverse_point_index_map.get(&point_idx).unwrap(); - point_sets[set_idx].push(*point); - } - } - - (commitment_map, point_sets) -} diff --git a/halo2_backend/src/poly/ipa/multiopen/prover.rs b/halo2_backend/src/poly/ipa/multiopen/prover.rs deleted file mode 100644 index e16582b080..0000000000 --- a/halo2_backend/src/poly/ipa/multiopen/prover.rs +++ /dev/null @@ -1,135 +0,0 @@ -use super::{construct_intermediate_sets, ChallengeX1, ChallengeX2, ChallengeX3, ChallengeX4}; -use crate::arithmetic::{eval_polynomial, kate_division, CurveAffine}; -use crate::poly::commitment::ParamsProver; -use crate::poly::commitment::{Blind, Prover}; -use crate::poly::ipa::commitment::{self, IPACommitmentScheme, ParamsIPA}; -use crate::poly::query::ProverQuery; -use crate::poly::{Coeff, Polynomial}; -use crate::transcript::{EncodedChallenge, TranscriptWrite}; - -use group::Curve; -use halo2_middleware::ff::Field; -use halo2_middleware::zal::traits::MsmAccel; -use rand_core::RngCore; -use std::io; -use std::marker::PhantomData; - -/// IPA multi-open prover -#[derive(Debug)] -pub struct ProverIPA<'params, C: CurveAffine> { - pub(crate) params: &'params ParamsIPA, -} - -impl<'params, C: CurveAffine> Prover<'params, IPACommitmentScheme> for ProverIPA<'params, C> { - const QUERY_INSTANCE: bool = true; - - fn new(params: &'params ParamsIPA) -> Self { - Self { params } - } - - /// Create a multi-opening proof - fn create_proof_with_engine<'com, Z: EncodedChallenge, T: TranscriptWrite, R, I>( - &self, - engine: &impl MsmAccel, - mut rng: R, - transcript: &mut T, - queries: I, - ) -> io::Result<()> - where - I: IntoIterator> + Clone, - R: RngCore, - { - let x_1: ChallengeX1<_> = transcript.squeeze_challenge_scalar(); - let x_2: ChallengeX2<_> = transcript.squeeze_challenge_scalar(); - - let (poly_map, point_sets) = construct_intermediate_sets(queries); - - // Collapse openings at same point sets together into single openings using - // x_1 challenge. - let mut q_polys: Vec>> = vec![None; point_sets.len()]; - let mut q_blinds = vec![Blind(C::Scalar::ZERO); point_sets.len()]; - - { - let mut accumulate = |set_idx: usize, - new_poly: &Polynomial, - blind: Blind| { - if let Some(poly) = &q_polys[set_idx] { - q_polys[set_idx] = Some(poly.clone() * *x_1 + new_poly); - } else { - q_polys[set_idx] = Some(new_poly.clone()); - } - q_blinds[set_idx] *= *x_1; - q_blinds[set_idx] += blind; - }; - - for commitment_data in poly_map.into_iter() { - accumulate( - commitment_data.set_index, // set_idx, - commitment_data.commitment.poly, // poly, - commitment_data.commitment.blind, // blind, - ); - } - } - - let q_prime_poly = point_sets - .iter() - .zip(q_polys.iter()) - .fold(None, |q_prime_poly, (points, poly)| { - let mut poly = points - .iter() - .fold(poly.clone().unwrap().values, |poly, point| { - kate_division(&poly, *point) - }); - poly.resize(self.params.n as usize, C::Scalar::ZERO); - let poly = Polynomial { - values: poly, - _marker: PhantomData, - }; - - if q_prime_poly.is_none() { - Some(poly) - } else { - q_prime_poly.map(|q_prime_poly| q_prime_poly * *x_2 + &poly) - } - }) - .unwrap(); - - let q_prime_blind = Blind(C::Scalar::random(&mut rng)); - let q_prime_commitment = self - .params - .commit(engine, &q_prime_poly, q_prime_blind) - .to_affine(); - - transcript.write_point(q_prime_commitment)?; - - let x_3: ChallengeX3<_> = transcript.squeeze_challenge_scalar(); - - // Prover sends u_i for all i, which correspond to the evaluation - // of each Q polynomial commitment at x_3. - for q_i_poly in &q_polys { - transcript.write_scalar(eval_polynomial(q_i_poly.as_ref().unwrap(), *x_3))?; - } - - let x_4: ChallengeX4<_> = transcript.squeeze_challenge_scalar(); - - let (p_poly, p_poly_blind) = q_polys.into_iter().zip(q_blinds).fold( - (q_prime_poly, q_prime_blind), - |(q_prime_poly, q_prime_blind), (poly, blind)| { - ( - q_prime_poly * *x_4 + &poly.unwrap(), - Blind((q_prime_blind.0 * (*x_4)) + blind.0), - ) - }, - ); - - commitment::create_proof_with_engine( - engine, - self.params, - rng, - transcript, - &p_poly, - p_poly_blind, - *x_3, - ) - } -} diff --git a/halo2_backend/src/poly/ipa/multiopen/verifier.rs b/halo2_backend/src/poly/ipa/multiopen/verifier.rs deleted file mode 100644 index 79133eeffa..0000000000 --- a/halo2_backend/src/poly/ipa/multiopen/verifier.rs +++ /dev/null @@ -1,151 +0,0 @@ -use std::fmt::Debug; -use std::marker::PhantomData; - -use halo2_middleware::ff::Field; - -use super::{construct_intermediate_sets, ChallengeX1, ChallengeX2, ChallengeX3, ChallengeX4}; -use crate::arithmetic::{eval_polynomial, lagrange_interpolate, CurveAffine}; -use crate::poly::commitment::{ParamsVerifier, Verifier, MSM}; -use crate::poly::ipa::commitment::IPACommitmentScheme; -use crate::poly::ipa::msm::MSMIPA; -use crate::poly::ipa::strategy::GuardIPA; -use crate::poly::query::{CommitmentReference, VerifierQuery}; -use crate::poly::Error; -use crate::transcript::{EncodedChallenge, TranscriptRead}; - -/// IPA multi-open verifier -#[derive(Debug)] -pub struct VerifierIPA { - _marker: PhantomData, -} - -impl<'params, C: CurveAffine> Verifier<'params, IPACommitmentScheme> for VerifierIPA { - type Guard = GuardIPA<'params, C>; - type MSMAccumulator = MSMIPA<'params, C>; - - const QUERY_INSTANCE: bool = true; - - fn new() -> Self { - Self { - _marker: PhantomData, - } - } - - fn verify_proof<'com, E: EncodedChallenge, T: TranscriptRead, I>( - &self, - transcript: &mut T, - queries: I, - mut msm: MSMIPA<'params, C>, - ) -> Result - where - 'params: 'com, - I: IntoIterator>> + Clone, - { - // Sample x_1 for compressing openings at the same point sets together - let x_1: ChallengeX1<_> = transcript.squeeze_challenge_scalar(); - - // Sample a challenge x_2 for keeping the multi-point quotient - // polynomial terms linearly independent. - let x_2: ChallengeX2<_> = transcript.squeeze_challenge_scalar(); - - let (commitment_map, point_sets) = construct_intermediate_sets(queries); - - // Compress the commitments and expected evaluations at x together. - // using the challenge x_1 - let empty_msm = ParamsVerifier::<'params, C>::empty_msm(msm.params); - let mut q_commitments: Vec<_> = vec![ - - (empty_msm, C::Scalar::ONE); // (accumulator, next x_1 power). - point_sets.len()]; - - // A vec of vecs of evals. The outer vec corresponds to the point set, - // while the inner vec corresponds to the points in a particular set. - let mut q_eval_sets = Vec::with_capacity(point_sets.len()); - for point_set in point_sets.iter() { - q_eval_sets.push(vec![C::Scalar::ZERO; point_set.len()]); - } - - { - let mut accumulate = |set_idx: usize, - new_commitment: CommitmentReference>, - evals: Vec| { - let (q_commitment, x_1_power) = &mut q_commitments[set_idx]; - match new_commitment { - CommitmentReference::Commitment(c) => { - q_commitment.append_term(*x_1_power, (*c).into()); - } - CommitmentReference::MSM(msm) => { - let mut msm = msm.clone(); - msm.scale(*x_1_power); - q_commitment.add_msm(&msm); - } - } - for (eval, set_eval) in evals.iter().zip(q_eval_sets[set_idx].iter_mut()) { - *set_eval += (*eval) * (*x_1_power); - } - *x_1_power *= *x_1; - }; - - // Each commitment corresponds to evaluations at a set of points. - // For each set, we collapse each commitment's evals pointwise. - // Run in order of increasing x_1 powers. - for commitment_data in commitment_map.into_iter().rev() { - accumulate( - commitment_data.set_index, // set_idx, - commitment_data.commitment, // commitment, - commitment_data.evals, // evals - ); - } - } - - // Obtain the commitment to the multi-point quotient polynomial f(X). - let q_prime_commitment = transcript.read_point().map_err(|_| Error::SamplingError)?; - - // Sample a challenge x_3 for checking that f(X) was committed to - // correctly. - let x_3: ChallengeX3<_> = transcript.squeeze_challenge_scalar(); - - // u is a vector containing the evaluations of the Q polynomial - // commitments at x_3 - let mut u = Vec::with_capacity(q_eval_sets.len()); - for _ in 0..q_eval_sets.len() { - u.push(transcript.read_scalar().map_err(|_| Error::SamplingError)?); - } - - // We can compute the expected msm_eval at x_3 using the u provided - // by the prover and from x_2 - let msm_eval = point_sets - .iter() - .zip(q_eval_sets.iter()) - .zip(u.iter()) - .fold( - C::Scalar::ZERO, - |msm_eval, ((points, evals), proof_eval)| { - let r_poly = lagrange_interpolate(points, evals); - let r_eval = eval_polynomial(&r_poly, *x_3); - let eval = points.iter().fold(*proof_eval - r_eval, |eval, point| { - eval * (*x_3 - point).invert().unwrap() - }); - msm_eval * (*x_2) + eval - }, - ); - - // Sample a challenge x_4 that we will use to collapse the openings of - // the various remaining polynomials at x_3 together. - let x_4: ChallengeX4<_> = transcript.squeeze_challenge_scalar(); - - // Compute the final commitment that has to be opened - msm.append_term(C::Scalar::ONE, q_prime_commitment.into()); - let (msm, v) = q_commitments.into_iter().zip(u.iter()).fold( - (msm, msm_eval), - |(mut msm, msm_eval), ((q_commitment, _), q_eval)| { - msm.scale(*x_4); - msm.add_msm(&q_commitment); - (msm, msm_eval * (*x_4) + q_eval) - }, - ); - - // Verify the opening proof - super::commitment::verify_proof(msm, transcript, *x_3, v) - } -} diff --git a/halo2_backend/src/poly/ipa/strategy.rs b/halo2_backend/src/poly/ipa/strategy.rs deleted file mode 100644 index fd9031d3f4..0000000000 --- a/halo2_backend/src/poly/ipa/strategy.rs +++ /dev/null @@ -1,163 +0,0 @@ -use super::commitment::{IPACommitmentScheme, ParamsIPA}; -use super::msm::MSMIPA; -use super::multiopen::VerifierIPA; -use crate::{ - plonk::Error, - poly::{ - commitment::MSM, - strategy::{Guard, VerificationStrategy}, - }, -}; -use group::Curve; -use halo2_middleware::ff::Field; -use halo2_middleware::zal::{impls::H2cEngine, traits::MsmAccel}; -use halo2curves::CurveAffine; -use rand_core::OsRng; - -/// Wrapper for verification accumulator -#[derive(Debug, Clone)] -pub struct GuardIPA<'params, C: CurveAffine> { - pub(crate) msm: MSMIPA<'params, C>, - pub(crate) neg_c: C::Scalar, - pub(crate) u: Vec, - pub(crate) u_packed: Vec, -} - -/// An accumulator instance consisting of an evaluation claim and a proof. -#[derive(Debug, Clone)] -pub struct Accumulator { - /// The claimed output of the linear-time polycommit opening protocol - pub g: C, - - /// A vector of challenges u_0, ..., u_{k - 1} sampled by the verifier, to - /// be used in computing G'_0. - pub u_packed: Vec, -} - -/// Define accumulator type as `MSMIPA` -impl<'params, C: CurveAffine> Guard> for GuardIPA<'params, C> { - type MSMAccumulator = MSMIPA<'params, C>; -} - -/// IPA specific operations -impl<'params, C: CurveAffine> GuardIPA<'params, C> { - /// Lets caller supply the challenges and obtain an MSM with updated - /// scalars and points. - pub fn use_challenges(mut self) -> MSMIPA<'params, C> { - let s = compute_s(&self.u, self.neg_c); - self.msm.add_to_g_scalars(&s); - - self.msm - } - - /// Lets caller supply the purported G point and simply appends - /// [-c] G to return an updated MSM. - pub fn use_g(mut self, g: C) -> (MSMIPA<'params, C>, Accumulator) { - self.msm.append_term(self.neg_c, g.into()); - - let accumulator = Accumulator { - g, - u_packed: self.u_packed, - }; - - (self.msm, accumulator) - } - - /// Computes G = ⟨s, params.g⟩ - pub fn compute_g(&self, engine: &impl MsmAccel) -> C { - let s = compute_s(&self.u, C::Scalar::ONE); - engine.msm(&s, &self.msm.params.g).to_affine() - } -} - -/// A verifier that checks multiple proofs in a batch. -#[derive(Debug)] -pub struct AccumulatorStrategy<'params, C: CurveAffine> { - msm: MSMIPA<'params, C>, -} - -impl<'params, C: CurveAffine> VerificationStrategy<'params, IPACommitmentScheme, VerifierIPA> - for AccumulatorStrategy<'params, C> -{ - fn new(params: &'params ParamsIPA) -> Self { - AccumulatorStrategy { - msm: MSMIPA::new(params), - } - } - - fn process( - mut self, - f: impl FnOnce(MSMIPA<'params, C>) -> Result, Error>, - ) -> Result { - self.msm.scale(C::Scalar::random(OsRng)); - let guard = f(self.msm)?; - - Ok(Self { - msm: guard.use_challenges(), - }) - } - - /// 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 { - // TODO: Verification is cheap, ZkAccel on verifier is not a priority. - self.msm.check(&H2cEngine::new()) - } -} - -/// 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> - for SingleStrategy<'params, C> -{ - 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)?; - Ok(Self { - msm: guard.use_challenges(), - }) - } - - /// 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 { - // TODO: Verification is cheap, ZkAccel on verifier is not a priority. - self.msm.check(&H2cEngine::new()) - } -} - -/// 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()); - let mut v = vec![F::ZERO; 1 << u.len()]; - v[0] = init; - - for (len, u_j) in u.iter().rev().enumerate().map(|(i, u_j)| (1 << i, u_j)) { - let (left, right) = v.split_at_mut(len); - let right = &mut right[0..len]; - right.copy_from_slice(left); - for v in right { - *v *= u_j; - } - } - - v -} diff --git a/halo2_backend/src/poly/kzg/multiopen/gwc/prover.rs b/halo2_backend/src/poly/kzg/multiopen/gwc/prover.rs index 4b9cda2470..add80bbfeb 100644 --- a/halo2_backend/src/poly/kzg/multiopen/gwc/prover.rs +++ b/halo2_backend/src/poly/kzg/multiopen/gwc/prover.rs @@ -30,8 +30,6 @@ where E::G1: CurveExt, E::G2Affine: SerdeCurveAffine, { - const QUERY_INSTANCE: bool = false; - fn new(params: &'params ParamsKZG) -> Self { Self { params } } diff --git a/halo2_backend/src/poly/kzg/multiopen/gwc/verifier.rs b/halo2_backend/src/poly/kzg/multiopen/gwc/verifier.rs index 3ac5065b09..196f330819 100644 --- a/halo2_backend/src/poly/kzg/multiopen/gwc/verifier.rs +++ b/halo2_backend/src/poly/kzg/multiopen/gwc/verifier.rs @@ -35,8 +35,6 @@ where type Guard = GuardKZG; type MSMAccumulator = DualMSM; - const QUERY_INSTANCE: bool = false; - fn new() -> Self { Self { _marker: PhantomData, diff --git a/halo2_backend/src/poly/kzg/multiopen/shplonk/prover.rs b/halo2_backend/src/poly/kzg/multiopen/shplonk/prover.rs index 194215e6da..3bdfc68a5d 100644 --- a/halo2_backend/src/poly/kzg/multiopen/shplonk/prover.rs +++ b/halo2_backend/src/poly/kzg/multiopen/shplonk/prover.rs @@ -111,8 +111,6 @@ where E::G1: CurveExt, E::G2Affine: SerdeCurveAffine, { - const QUERY_INSTANCE: bool = false; - fn new(params: &'params ParamsKZG) -> Self { Self { params } } diff --git a/halo2_backend/src/poly/kzg/multiopen/shplonk/verifier.rs b/halo2_backend/src/poly/kzg/multiopen/shplonk/verifier.rs index a67a555733..4fad8dece3 100644 --- a/halo2_backend/src/poly/kzg/multiopen/shplonk/verifier.rs +++ b/halo2_backend/src/poly/kzg/multiopen/shplonk/verifier.rs @@ -39,8 +39,6 @@ where type Guard = GuardKZG; type MSMAccumulator = DualMSM; - const QUERY_INSTANCE: bool = false; - fn new() -> Self { Self { _marker: PhantomData, diff --git a/halo2_backend/src/poly/multiopen_test.rs b/halo2_backend/src/poly/multiopen_test.rs index e40d203a8a..a2246ac6f9 100644 --- a/halo2_backend/src/poly/multiopen_test.rs +++ b/halo2_backend/src/poly/multiopen_test.rs @@ -11,90 +11,14 @@ mod test { EvaluationDomain, }; use crate::transcript::{ - Blake2bRead, Blake2bWrite, Challenge255, EncodedChallenge, Keccak256Read, Keccak256Write, - TranscriptReadBuffer, TranscriptWriterBuffer, + Blake2bRead, Blake2bWrite, Challenge255, EncodedChallenge, TranscriptReadBuffer, + TranscriptWriterBuffer, }; use group::Curve; use halo2_middleware::ff::WithSmallOrderMulGroup; use halo2_middleware::zal::{impls::H2cEngine, traits::MsmAccel}; use rand_core::OsRng; - #[test] - fn test_roundtrip_ipa() { - use crate::poly::ipa::commitment::{IPACommitmentScheme, ParamsIPA}; - use crate::poly::ipa::multiopen::{ProverIPA, VerifierIPA}; - use crate::poly::ipa::strategy::AccumulatorStrategy; - use halo2curves::pasta::EqAffine; - - const K: u32 = 4; - - let engine = H2cEngine::new(); - let params = ParamsIPA::::new(K); - - let proof = create_proof::< - IPACommitmentScheme, - ProverIPA<_>, - _, - Blake2bWrite<_, _, Challenge255<_>>, - >(&engine, ¶ms); - - let verifier_params = params; - - verify::< - IPACommitmentScheme, - VerifierIPA<_>, - _, - Blake2bRead<_, _, Challenge255<_>>, - AccumulatorStrategy<_>, - >(&verifier_params, &proof[..], false); - - verify::< - IPACommitmentScheme, - VerifierIPA<_>, - _, - Blake2bRead<_, _, Challenge255<_>>, - AccumulatorStrategy<_>, - >(&verifier_params, &proof[..], true); - } - - #[test] - fn test_roundtrip_ipa_keccak() { - use crate::poly::ipa::commitment::{IPACommitmentScheme, ParamsIPA}; - use crate::poly::ipa::multiopen::{ProverIPA, VerifierIPA}; - use crate::poly::ipa::strategy::AccumulatorStrategy; - use halo2curves::pasta::EqAffine; - - const K: u32 = 4; - - let engine = H2cEngine::new(); - let params = ParamsIPA::::new(K); - - let proof = create_proof::< - IPACommitmentScheme, - ProverIPA<_>, - _, - Keccak256Write<_, _, Challenge255<_>>, - >(&engine, ¶ms); - - let verifier_params = params; - - verify::< - IPACommitmentScheme, - VerifierIPA<_>, - _, - Keccak256Read<_, _, Challenge255<_>>, - AccumulatorStrategy<_>, - >(&verifier_params, &proof[..], false); - - verify::< - IPACommitmentScheme, - VerifierIPA<_>, - _, - Keccak256Read<_, _, Challenge255<_>>, - AccumulatorStrategy<_>, - >(&verifier_params, &proof[..], true); - } - #[test] fn test_roundtrip_gwc() { use crate::poly::kzg::commitment::{KZGCommitmentScheme, ParamsKZG}; @@ -280,17 +204,14 @@ mod test { ProverQuery { point: x.get_scalar(), poly: &ax, - blind, }, ProverQuery { point: x.get_scalar(), poly: &bx, - blind, }, ProverQuery { point: y.get_scalar(), poly: &cx, - blind, }, ] .to_vec(); diff --git a/halo2_backend/src/poly/query.rs b/halo2_backend/src/poly/query.rs index 30be4fbec7..56b5f3e2f8 100644 --- a/halo2_backend/src/poly/query.rs +++ b/halo2_backend/src/poly/query.rs @@ -23,8 +23,6 @@ pub struct ProverQuery<'com, C: CurveAffine> { pub(crate) point: C::Scalar, /// Coefficients of polynomial pub(crate) poly: &'com Polynomial, - /// Blinding factor of polynomial - pub(crate) blind: Blind, } impl<'com, C> ProverQuery<'com, C> @@ -35,9 +33,9 @@ where pub fn new( point: C::Scalar, poly: &'com Polynomial, - blind: Blind, + _blind: Blind, ) -> Self { - ProverQuery { point, poly, blind } + ProverQuery { point, poly } } } @@ -45,7 +43,6 @@ where #[derive(Copy, Clone)] pub struct PolynomialPointer<'com, C: CurveAffine> { pub(crate) poly: &'com Polynomial, - pub(crate) blind: Blind, } impl<'com, C: CurveAffine> PartialEq for PolynomialPointer<'com, C> { @@ -65,10 +62,7 @@ impl<'com, C: CurveAffine> Query for ProverQuery<'com, C> { eval_polynomial(&self.poly[..], self.get_point()) } fn get_commitment(&self) -> Self::Commitment { - PolynomialPointer { - poly: self.poly, - blind: self.blind, - } + PolynomialPointer { poly: self.poly } } } diff --git a/halo2_frontend/src/dev/cost_model.rs b/halo2_frontend/src/dev/cost_model.rs index 49bec78197..8ddf0baaa0 100644 --- a/halo2_frontend/src/dev/cost_model.rs +++ b/halo2_frontend/src/dev/cost_model.rs @@ -14,8 +14,6 @@ use super::MockProver; /// Supported commitment schemes #[derive(Debug, Eq, PartialEq)] pub enum CommitmentScheme { - /// Inner Product Argument commitment scheme - IPA, /// KZG with GWC19 multi-open strategy KZGGWC, /// KZG with BDFG20 multi-open strategy @@ -193,14 +191,6 @@ impl CostOptions { let multiopen = comp_bytes(1, point_sets); let polycomm = match comm_scheme { - CommitmentScheme::IPA => { - // Polycommit IPA: - // - s_poly commitment (COMM bytes) - // - inner product argument (k rounds * 2 * COMM bytes) - // - a (SCALAR bytes) - // - xi (SCALAR bytes) - comp_bytes(1 + 2 * self.k, 2) - } CommitmentScheme::KZGGWC => { let mut nr_rotations = HashSet::new(); for poly in self.advice.iter() { diff --git a/halo2_proofs/benches/plonk.rs b/halo2_proofs/benches/plonk.rs index c0eb4ee7dd..9306011304 100644 --- a/halo2_proofs/benches/plonk.rs +++ b/halo2_proofs/benches/plonk.rs @@ -2,21 +2,19 @@ extern crate criterion; use group::ff::Field; +use halo2_backend::plonk::verifier::verify_proof; +use halo2_debug::test_rng; use halo2_proofs::circuit::{Cell, Layouter, SimpleFloorPlanner, Value}; use halo2_proofs::plonk::*; -use halo2_proofs::poly::{commitment::ParamsProver, Rotation}; +use halo2_proofs::poly::kzg::commitment::{KZGCommitmentScheme, ParamsKZG}; +use halo2_proofs::poly::kzg::multiopen::{ProverSHPLONK, VerifierSHPLONK}; +use halo2_proofs::poly::kzg::strategy::SingleStrategy; +use halo2_proofs::poly::Rotation; use halo2_proofs::transcript::{Blake2bRead, Blake2bWrite, Challenge255}; -use halo2curves::pasta::{EqAffine, Fp}; +use halo2curves::bn256::{Bn256, Fr, G1Affine}; use rand_core::OsRng; -use halo2_proofs::{ - poly::ipa::{ - commitment::{IPACommitmentScheme, ParamsIPA}, - multiopen::ProverIPA, - strategy::SingleStrategy, - }, - transcript::{TranscriptReadBuffer, TranscriptWriterBuffer}, -}; +use halo2_proofs::transcript::{TranscriptReadBuffer, TranscriptWriterBuffer}; use std::marker::PhantomData; @@ -264,27 +262,30 @@ fn criterion_benchmark(c: &mut Criterion) { } } - fn keygen(k: u32) -> (ParamsIPA, ProvingKey) { - let params: ParamsIPA = ParamsIPA::new(k); - let empty_circuit: MyCircuit = MyCircuit { - a: Value::unknown(), + fn key_and_circuit_gen(k: u32) -> (ParamsKZG, ProvingKey, MyCircuit) { + // Setup + let mut rng = test_rng(); + let params = ParamsKZG::::setup(k, &mut rng); + + let circuit: MyCircuit = MyCircuit { + a: Value::known(Fr::random(rng)), k, }; - let vk = keygen_vk(¶ms, &empty_circuit).expect("keygen_vk should not fail"); - let pk = keygen_pk(¶ms, vk, &empty_circuit).expect("keygen_pk should not fail"); - (params, pk) + + let vk = keygen_vk(¶ms, &circuit).expect("keygen_vk should not fail"); + let pk = keygen_pk(¶ms, vk.clone(), &circuit).expect("keygen_pk should not fail"); + (params, pk, circuit) } - fn prover(k: u32, params: &ParamsIPA, pk: &ProvingKey) -> Vec { + fn prover( + circuit: MyCircuit, + params: &ParamsKZG, + pk: &ProvingKey, + ) -> Vec { let rng = OsRng; - let circuit: MyCircuit = MyCircuit { - a: Value::known(Fp::random(rng)), - k, - }; - - let mut transcript = Blake2bWrite::<_, _, Challenge255>::init(vec![]); - create_proof::, ProverIPA, _, _, _, _>( + let mut transcript = Blake2bWrite::<_, G1Affine, Challenge255<_>>::init(vec![]); + create_proof::, ProverSHPLONK<'_, Bn256>, _, _, _, _>( params, pk, &[circuit], @@ -296,14 +297,20 @@ fn criterion_benchmark(c: &mut Criterion) { transcript.finalize() } - fn verifier(params: &ParamsIPA, vk: &VerifyingKey, proof: &[u8]) { - let mut transcript = Blake2bRead::<_, _, Challenge255<_>>::init(proof); - assert!(verify_proof_multi::<_, _, _, _, SingleStrategy<_>>( - params, - vk, - &[vec![]], - &mut transcript - )); + fn verifier(params: &ParamsKZG, vk: &VerifyingKey, proof: &[u8]) { + let mut verifier_transcript = Blake2bRead::<_, G1Affine, Challenge255<_>>::init(proof); + let verifier_params = params.verifier_params(); + + assert!( + verify_proof::< + KZGCommitmentScheme, + VerifierSHPLONK, + _, + _, + SingleStrategy<_>, + >(&verifier_params, vk, vec![vec![]], &mut verifier_transcript), + "failed to verify proof" + ); } let k_range = 8..=16; @@ -312,7 +319,7 @@ fn criterion_benchmark(c: &mut Criterion) { keygen_group.sample_size(10); for k in k_range.clone() { keygen_group.bench_with_input(BenchmarkId::from_parameter(k), &k, |b, &k| { - b.iter(|| keygen(k)); + b.iter(|| key_and_circuit_gen(k)); }); } keygen_group.finish(); @@ -320,13 +327,13 @@ fn criterion_benchmark(c: &mut Criterion) { let mut prover_group = c.benchmark_group("plonk-prover"); prover_group.sample_size(10); for k in k_range.clone() { - let (params, pk) = keygen(k); + let (params, pk, circuit) = key_and_circuit_gen(k); prover_group.bench_with_input( BenchmarkId::from_parameter(k), &(k, ¶ms, &pk), - |b, &(k, params, pk)| { - b.iter(|| prover(k, params, pk)); + |b, &(_k, params, pk)| { + b.iter(|| prover(circuit.clone(), params, pk)); }, ); } @@ -334,8 +341,8 @@ fn criterion_benchmark(c: &mut Criterion) { let mut verifier_group = c.benchmark_group("plonk-verifier"); for k in k_range { - let (params, pk) = keygen(k); - let proof = prover(k, ¶ms, &pk); + let (params, pk, circuit) = key_and_circuit_gen(k); + let proof = prover(circuit, ¶ms, &pk); verifier_group.bench_with_input( BenchmarkId::from_parameter(k), diff --git a/halo2_proofs/src/lib.rs b/halo2_proofs/src/lib.rs index 03386ea0e8..5437c021fa 100644 --- a/halo2_proofs/src/lib.rs +++ b/halo2_proofs/src/lib.rs @@ -43,7 +43,7 @@ pub mod dev { /// the committed polynomials at arbitrary points. pub mod poly { pub use halo2_backend::poly::VerificationStrategy; - pub use halo2_backend::poly::{commitment, ipa, kzg, EvaluationDomain}; + pub use halo2_backend::poly::{commitment, kzg, EvaluationDomain}; pub use halo2_middleware::poly::Rotation; } /// This module contains utilities and traits for dealing with Fiat-Shamir diff --git a/halo2_proofs/tests/plonk_api.rs b/halo2_proofs/tests/plonk_api.rs index 0b8264a85f..bd41641435 100644 --- a/halo2_proofs/tests/plonk_api.rs +++ b/halo2_proofs/tests/plonk_api.rs @@ -643,566 +643,6 @@ fn plonk_api() { ); } - 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::AccumulatorStrategy; - use halo2curves::pasta::EqAffine; - - type Scheme = IPACommitmentScheme; - bad_keys!(Scheme); - - let mut rng = test_rng(); - let params = ParamsIPA::::new(K); - - let pk = keygen::>(¶ms); - - let proof = create_proof::<_, ProverIPA<_>, _, _, Blake2bWrite<_, _, Challenge255<_>>>( - &mut rng, ¶ms, &pk, - ); - - let verifier_params = params; - - verify_proof::< - _, - VerifierIPA<_>, - _, - Blake2bRead<_, _, Challenge255<_>>, - AccumulatorStrategy<_>, - >(&verifier_params, pk.get_vk(), &proof[..]); - - // Check that the verification key has not changed unexpectedly - { - // panic!("{:#?}", pk.get_vk().pinned()); - assert_eq!( - format!("{:#?}", pk.get_vk().pinned()), - r#"PinnedVerificationKey { - base_modulus: "0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001", - scalar_modulus: "0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001", - domain: PinnedEvaluationDomain { - k: 5, - extended_k: 7, - omega: 0x0cc3380dc616f2e1daf29ad1560833ed3baea3393eceb7bc8fa36376929b78cc, - }, - cs: PinnedConstraintSystem { - num_fixed_columns: 7, - num_advice_columns: 5, - num_instance_columns: 1, - num_challenges: 0, - advice_column_phase: [ - 0, - 0, - 0, - 0, - 0, - ], - challenge_phase: [], - gates: [ - Sum( - Sum( - Sum( - Sum( - Product( - Var( - Query( - QueryBack { - index: 0, - column: ColumnMid { - column_type: Advice, - index: 1, - }, - rotation: Rotation( - 0, - ), - }, - ), - ), - Var( - Query( - QueryBack { - index: 0, - column: ColumnMid { - column_type: Fixed, - index: 2, - }, - rotation: Rotation( - 0, - ), - }, - ), - ), - ), - Product( - Var( - Query( - QueryBack { - index: 1, - column: ColumnMid { - column_type: Advice, - index: 2, - }, - rotation: Rotation( - 0, - ), - }, - ), - ), - Var( - Query( - QueryBack { - index: 1, - column: ColumnMid { - column_type: Fixed, - index: 3, - }, - rotation: Rotation( - 0, - ), - }, - ), - ), - ), - ), - Product( - Product( - Var( - Query( - QueryBack { - index: 0, - column: ColumnMid { - column_type: Advice, - index: 1, - }, - rotation: Rotation( - 0, - ), - }, - ), - ), - Var( - Query( - QueryBack { - index: 1, - column: ColumnMid { - column_type: Advice, - index: 2, - }, - rotation: Rotation( - 0, - ), - }, - ), - ), - ), - Var( - Query( - QueryBack { - index: 2, - column: ColumnMid { - column_type: Fixed, - index: 1, - }, - rotation: Rotation( - 0, - ), - }, - ), - ), - ), - ), - Negated( - Product( - Var( - Query( - QueryBack { - index: 2, - column: ColumnMid { - column_type: Advice, - index: 3, - }, - rotation: Rotation( - 0, - ), - }, - ), - ), - Var( - Query( - QueryBack { - index: 3, - column: ColumnMid { - column_type: Fixed, - index: 4, - }, - rotation: Rotation( - 0, - ), - }, - ), - ), - ), - ), - ), - Product( - Var( - Query( - QueryBack { - index: 4, - column: ColumnMid { - column_type: Fixed, - index: 0, - }, - rotation: Rotation( - 0, - ), - }, - ), - ), - Product( - Var( - Query( - QueryBack { - index: 3, - column: ColumnMid { - column_type: Advice, - index: 4, - }, - rotation: Rotation( - 1, - ), - }, - ), - ), - Var( - Query( - QueryBack { - index: 4, - column: ColumnMid { - column_type: Advice, - index: 0, - }, - rotation: Rotation( - -1, - ), - }, - ), - ), - ), - ), - ), - Product( - Var( - Query( - QueryBack { - index: 5, - column: ColumnMid { - column_type: Fixed, - index: 5, - }, - rotation: Rotation( - 0, - ), - }, - ), - ), - Sum( - Var( - Query( - QueryBack { - index: 0, - column: ColumnMid { - column_type: Advice, - index: 1, - }, - rotation: Rotation( - 0, - ), - }, - ), - ), - Negated( - Var( - Query( - QueryBack { - index: 0, - column: ColumnMid { - column_type: Instance, - index: 0, - }, - rotation: Rotation( - 0, - ), - }, - ), - ), - ), - ), - ), - ], - advice_queries: [ - ( - ColumnMid { - column_type: Advice, - index: 1, - }, - Rotation( - 0, - ), - ), - ( - ColumnMid { - column_type: Advice, - index: 2, - }, - Rotation( - 0, - ), - ), - ( - ColumnMid { - column_type: Advice, - index: 3, - }, - Rotation( - 0, - ), - ), - ( - ColumnMid { - column_type: Advice, - index: 4, - }, - Rotation( - 1, - ), - ), - ( - ColumnMid { - column_type: Advice, - index: 0, - }, - Rotation( - -1, - ), - ), - ( - ColumnMid { - column_type: Advice, - index: 0, - }, - Rotation( - 0, - ), - ), - ( - ColumnMid { - column_type: Advice, - index: 4, - }, - Rotation( - 0, - ), - ), - ], - instance_queries: [ - ( - ColumnMid { - column_type: Instance, - index: 0, - }, - Rotation( - 0, - ), - ), - ], - fixed_queries: [ - ( - ColumnMid { - column_type: Fixed, - index: 2, - }, - Rotation( - 0, - ), - ), - ( - ColumnMid { - column_type: Fixed, - index: 3, - }, - Rotation( - 0, - ), - ), - ( - ColumnMid { - column_type: Fixed, - index: 1, - }, - Rotation( - 0, - ), - ), - ( - ColumnMid { - column_type: Fixed, - index: 4, - }, - Rotation( - 0, - ), - ), - ( - ColumnMid { - column_type: Fixed, - index: 0, - }, - Rotation( - 0, - ), - ), - ( - ColumnMid { - column_type: Fixed, - index: 5, - }, - Rotation( - 0, - ), - ), - ( - ColumnMid { - column_type: Fixed, - index: 6, - }, - Rotation( - 0, - ), - ), - ], - permutation: ArgumentMid { - columns: [ - ColumnMid { - column_type: Advice, - index: 1, - }, - ColumnMid { - column_type: Advice, - index: 2, - }, - ColumnMid { - column_type: Advice, - index: 3, - }, - ColumnMid { - column_type: Fixed, - index: 0, - }, - ColumnMid { - column_type: Advice, - index: 0, - }, - ColumnMid { - column_type: Advice, - index: 4, - }, - ColumnMid { - column_type: Instance, - index: 0, - }, - ColumnMid { - column_type: Fixed, - index: 1, - }, - ColumnMid { - column_type: Fixed, - index: 2, - }, - ColumnMid { - column_type: Fixed, - index: 3, - }, - ColumnMid { - column_type: Fixed, - index: 4, - }, - ColumnMid { - column_type: Fixed, - index: 5, - }, - ], - }, - lookups: [ - Argument { - name: "lookup", - input_expressions: [ - Var( - Query( - QueryBack { - index: 0, - column: ColumnMid { - column_type: Advice, - index: 1, - }, - rotation: Rotation( - 0, - ), - }, - ), - ), - ], - table_expressions: [ - Var( - Query( - QueryBack { - index: 6, - column: ColumnMid { - column_type: Fixed, - index: 6, - }, - rotation: Rotation( - 0, - ), - }, - ), - ), - ], - }, - ], - shuffles: [], - minimum_degree: None, - }, - fixed_commitments: [ - (0x2bbc94ef7b22aebef24f9a4b0cc1831882548b605171366017d45c3e6fd92075, 0x082b801a6e176239943bfb759fb02138f47a5c8cc4aa7fa0af559fde4e3abd97), - (0x2bf5082b105b2156ed0e9c5b8e42bf2a240b058f74a464d080e9585274dd1e84, 0x222ad83cee7777e7a160585e212140e5e770dd8d1df788d869b5ee483a5864fb), - (0x374a656456a0aae7429b23336f825752b575dd5a44290ff614946ee59d6a20c0, 0x054491e187e6e3460e7601fb54ae10836d34d420026f96316f0c5c62f86db9b8), - (0x374a656456a0aae7429b23336f825752b575dd5a44290ff614946ee59d6a20c0, 0x054491e187e6e3460e7601fb54ae10836d34d420026f96316f0c5c62f86db9b8), - (0x02e62cd68370b13711139a08cbcdd889e800a272b9ea10acc90880fff9d89199, 0x1a96c468cb0ce77065d3a58f1e55fea9b72d15e44c01bba1e110bd0cbc6e9bc6), - (0x224ef42758215157d3ee48fb8d769da5bddd35e5929a90a4a89736f5c4b5ae9b, 0x11bc3a1e08eb320cde764f1492ecef956d71e996e2165f7a9a30ad2febb511c1), - (0x2d5415bf917fcac32bfb705f8ca35cb12d9bad52aa33ccca747350f9235d3a18, 0x2b2921f815fad504052512743963ef20ed5b401d20627793b006413e73fe4dd4), - ], - permutation: VerifyingKey { - commitments: [ - (0x1347b4b385837977a96b87f199c6a9a81520015539d1e8fa79429bb4ca229a00, 0x2168e404cabef513654d6ff516cde73f0ba87e3dc84e4b940ed675b5f66f3884), - (0x0e6d69cd2455ec43be640f6397ed65c9e51b1d8c0fd2216339314ff37ade122a, 0x222ed6dc8cfc9ea26dcc10b9d4add791ada60f2b5a63ee1e4635f88aa0c96654), - (0x13c447846f48c41a5e0675ccf88ebc0cdef2c96c51446d037acb866d24255785, 0x1f0b5414fc5e8219dbfab996eed6129d831488b2386a8b1a63663938903bd63a), - (0x1aae6470aa662b8fda003894ddef5fedd03af318b3231683039d2fac9cab05b9, 0x08832d91ae69e99cd07d096c7a4a284a69e6a16227cbb07932a0cdc56914f3a6), - (0x0850521b0f8ac7dd0550fe3e25c840837076e9635067ed623b81d5cbac5944d9, 0x0c25d65d1038d0a92c72e5fccd96c1caf07801c3c8233290bb292e0c38c256fa), - (0x12febcf696badd970750eabf75dd3ced4c2f54f93519bcee23849025177d2014, 0x0a05ab3cd42c9fbcc1bbfcf9269951640cc9920761c87cf8e211ba73c8d9f90f), - (0x053904bdde8cfead3b517bb4f6ded3e699f8b94ca6156a9dd2f92a2a05a7ec5a, 0x16753ff97c0d82ff586bb7a07bf7f27a92df90b3617fa5e75d4f55c3b0ef8711), - (0x3804548f6816452747a5b542fa5656353fc989db40d69e9e27d6f973b5deebb0, 0x389a44d5037866dd83993af75831a5f90a18ad5244255aa5bd2c922cc5853055), - (0x003a9f9ca71c7c0b832c802220915f6fc8d840162bdde6b0ea05d25fb95559e3, 0x091247ca19d6b73887cd7f68908cbf0db0b47459b7c82276bbdb8a1c937e2438), - (0x3eaa38689d9e391c8a8fafab9568f20c45816321d38f309d4cc37f4b1601af72, 0x247f8270a462ea88450221a56aa6b55d2bc352b80b03501e99ea983251ceea13), - (0x394437571f9de32dccdc546fd4737772d8d92593c85438aa3473243997d5acc8, 0x14924ec6e3174f1fab7f0ce7070c22f04bbd0a0ecebdfc5c94be857f25493e95), - (0x3d907e0591343bd285c2c846f3e871a6ac70d80ec29e9500b8cb57f544e60202, 0x1034e48df35830244cabea076be8a16d67d7896e27c6ac22b285d017105da9c3), - ], - }, -}"# - ); - } - } - - test_plonk_api_ipa(); test_plonk_api_gwc(); test_plonk_api_shplonk(); } diff --git a/halo2_proofs/tests/shuffle.rs b/halo2_proofs/tests/shuffle.rs index 5c8fe9fc1e..462955c23c 100644 --- a/halo2_proofs/tests/shuffle.rs +++ b/halo2_proofs/tests/shuffle.rs @@ -1,23 +1,20 @@ use ff::{BatchInvert, FromUniformBytes}; use halo2_debug::test_rng; use halo2_proofs::{ - arithmetic::{CurveAffine, Field}, + arithmetic::Field, circuit::{floor_planner::V1, Layouter, Value}, dev::{metadata, FailureLocation, MockProver, VerifyFailure}, - halo2curves::pasta::EqAffine, plonk::*, - poly::{ - commitment::ParamsProver, - ipa::{ - commitment::{IPACommitmentScheme, ParamsIPA}, - multiopen::{ProverIPA, VerifierIPA}, - strategy::AccumulatorStrategy, - }, + poly::kzg::{ + commitment::{KZGCommitmentScheme, ParamsKZG}, + multiopen::{ProverSHPLONK, VerifierSHPLONK}, + strategy::SingleStrategy, }, transcript::{ Blake2bRead, Blake2bWrite, Challenge255, TranscriptReadBuffer, TranscriptWriterBuffer, }, }; +use halo2curves::bn256::{Bn256, Fr, G1Affine}; use rand_core::RngCore; use std::iter; @@ -269,46 +266,48 @@ fn test_mock_prover, const W: usize, const H: usiz }; } -fn test_prover( +fn test_prover( k: u32, - circuit: MyCircuit, + circuit: MyCircuit, expected: bool, -) -> Vec -where - C::Scalar: FromUniformBytes<64>, -{ - let rng = test_rng(); - - let params = ParamsIPA::::new(k); - let vk = keygen_vk(¶ms, &circuit).unwrap(); - let pk = keygen_pk(¶ms, vk, &circuit).unwrap(); - - let proof = { - let mut transcript = Blake2bWrite::<_, _, Challenge255<_>>::init(vec![]); - - create_proof::, ProverIPA, _, _, _, _>( - ¶ms, - &pk, - &[circuit], - &[vec![]], - rng, - &mut transcript, - ) - .expect("proof generation should not fail"); - - transcript.finalize() - }; - - let accepted = { - let mut transcript = Blake2bRead::<_, _, Challenge255<_>>::init(&proof[..]); - - verify_proof_multi::, VerifierIPA, _, _, AccumulatorStrategy>( - ¶ms, - pk.get_vk(), - &[vec![]], - &mut transcript, - ) - }; +) -> Vec { + let instances = vec![vec![]]; + + // Setup + let mut rng = test_rng(); + let params = ParamsKZG::::setup(k, &mut rng); + let vk = keygen_vk(¶ms, &circuit).expect("keygen_vk should not fail"); + let pk = keygen_pk(¶ms, vk.clone(), &circuit).expect("keygen_pk should not fail"); + + let mut transcript = Blake2bWrite::<_, G1Affine, Challenge255<_>>::init(vec![]); + create_proof::, ProverSHPLONK<'_, Bn256>, _, _, _, _>( + ¶ms, + &pk, + &[circuit], + &instances, + &mut rng, + &mut transcript, + ) + .expect("proof generation should not fail"); + let proof = transcript.finalize(); + + // Verify + let mut verifier_transcript = + Blake2bRead::<_, G1Affine, Challenge255<_>>::init(proof.as_slice()); + let verifier_params = params.verifier_params(); + + let accepted = verify_proof_multi::< + KZGCommitmentScheme, + VerifierSHPLONK, + _, + _, + SingleStrategy<_>, + >( + &verifier_params, + &vk, + instances.as_slice(), + &mut verifier_transcript, + ); assert_eq!(accepted, expected); @@ -326,8 +325,8 @@ fn test_shuffle() { test_mock_prover(K, circuit.clone(), Ok(())); halo2_debug::test_result( - || test_prover::(K, circuit.clone(), true), - "08d9c3129b4e2f6dd63cfc2cc23577fb7a39d5f8b333e3fb4e1eb2b223059338", + || test_prover::(K, circuit.clone(), true), + "2a91b131950f5c9d9bf8d6486caf3870edcdb772d0021bead607076497762fac", ); #[cfg(not(feature = "sanity-checks"))] @@ -352,8 +351,8 @@ fn test_shuffle() { )]), ); halo2_debug::test_result( - || test_prover::(K, circuit.clone(), false), - "27ad558ee60a6675911b87a0df5de49d7c9b5673d723bb05a9811aa33bf486d1", + || test_prover::(K, circuit.clone(), false), + "e3702897ecf9e9ea052887184fae88e499ed34669e8861c5b2e53c2f1d54e055", ); } } diff --git a/halo2_proofs/tests/shuffle_api.rs b/halo2_proofs/tests/shuffle_api.rs index 1791790b23..d3d26ee9f6 100644 --- a/halo2_proofs/tests/shuffle_api.rs +++ b/halo2_proofs/tests/shuffle_api.rs @@ -1,8 +1,9 @@ use std::{marker::PhantomData, vec}; -use ff::FromUniformBytes; use halo2_debug::test_rng; -use halo2_proofs::poly::commitment::ParamsProver; +use halo2_proofs::poly::kzg::commitment::{KZGCommitmentScheme, ParamsKZG}; +use halo2_proofs::poly::kzg::multiopen::{ProverSHPLONK, VerifierSHPLONK}; +use halo2_proofs::poly::kzg::strategy::SingleStrategy; use halo2_proofs::{ arithmetic::Field, circuit::{Layouter, SimpleFloorPlanner, Value}, @@ -10,17 +11,13 @@ use halo2_proofs::{ create_proof, keygen_pk, keygen_vk, verify_proof_multi, Advice, Circuit, Column, ConstraintSystem, ErrorFront, Fixed, Selector, }, - poly::ipa::{ - commitment::{IPACommitmentScheme, ParamsIPA}, - multiopen::{ProverIPA, VerifierIPA}, - strategy::AccumulatorStrategy, - }, poly::Rotation, transcript::{ Blake2bRead, Blake2bWrite, Challenge255, TranscriptReadBuffer, TranscriptWriterBuffer, }, }; -use halo2curves::{pasta::EqAffine, CurveAffine}; +use halo2curves::bn256::G1Affine; +use halo2curves::bn256::{Bn256, Fr}; struct ShuffleChip { config: ShuffleConfig, @@ -145,42 +142,44 @@ impl Circuit for MyCircuit { } } -fn test_prover(k: u32, circuit: MyCircuit, expected: bool) -> Vec -where - C::Scalar: FromUniformBytes<64>, -{ - let rng = test_rng(); - - let params = ParamsIPA::::new(k); - let vk = keygen_vk(¶ms, &circuit).unwrap(); - let pk = keygen_pk(¶ms, vk, &circuit).unwrap(); - - let proof = { - let mut transcript = Blake2bWrite::<_, _, Challenge255<_>>::init(vec![]); - - create_proof::, ProverIPA, _, _, _, _>( - ¶ms, - &pk, - &[circuit], - &[vec![]], - rng, - &mut transcript, - ) - .expect("proof generation should not fail"); - - transcript.finalize() - }; - - let accepted = { - let mut transcript = Blake2bRead::<_, _, Challenge255<_>>::init(&proof[..]); - - verify_proof_multi::, VerifierIPA, _, _, AccumulatorStrategy<_>>( - ¶ms, - pk.get_vk(), - &[vec![]], - &mut transcript, - ) - }; +fn test_prover(k: u32, circuit: MyCircuit, expected: bool) -> Vec { + // Setup + let mut rng = test_rng(); + let params = ParamsKZG::::setup(k, &mut rng); + let vk = keygen_vk(¶ms, &circuit).expect("keygen_vk should not fail"); + let pk = keygen_pk(¶ms, vk.clone(), &circuit).expect("keygen_pk should not fail"); + + let instances = vec![vec![]]; + + let mut transcript = Blake2bWrite::<_, G1Affine, Challenge255<_>>::init(vec![]); + create_proof::, ProverSHPLONK<'_, Bn256>, _, _, _, _>( + ¶ms, + &pk, + &[circuit], + &instances, + &mut rng, + &mut transcript, + ) + .expect("proof generation should not fail"); + let proof = transcript.finalize(); + + // Verify + let mut verifier_transcript = + Blake2bRead::<_, G1Affine, Challenge255<_>>::init(proof.as_slice()); + let verifier_params = params.verifier_params(); + + let accepted = verify_proof_multi::< + KZGCommitmentScheme, + VerifierSHPLONK, + _, + _, + SingleStrategy<_>, + >( + &verifier_params, + &vk, + instances.as_slice(), + &mut verifier_transcript, + ); assert_eq!(accepted, expected); @@ -189,31 +188,29 @@ where #[test] fn test_shuffle_api() { + use halo2_proofs::dev::MockProver; + const K: u32 = 4; + let input_0 = [1, 2, 4, 1] + .map(|e: u64| Value::known(Fr::from(e))) + .to_vec(); + let input_1 = [10, 20, 40, 10].map(Fr::from).to_vec(); + let shuffle_0 = [4, 1, 1, 2] + .map(|e: u64| Value::known(Fr::from(e))) + .to_vec(); + let shuffle_1 = [40, 10, 10, 20] + .map(|e: u64| Value::known(Fr::from(e))) + .to_vec(); + let circuit = MyCircuit { + input_0, + input_1, + shuffle_0, + shuffle_1, + }; + let prover = MockProver::run(K, &circuit, vec![]).unwrap(); + prover.assert_satisfied(); + halo2_debug::test_result( - || { - use halo2_proofs::dev::MockProver; - use halo2curves::pasta::Fp; - const K: u32 = 4; - let input_0 = [1, 2, 4, 1] - .map(|e: u64| Value::known(Fp::from(e))) - .to_vec(); - let input_1 = [10, 20, 40, 10].map(Fp::from).to_vec(); - let shuffle_0 = [4, 1, 1, 2] - .map(|e: u64| Value::known(Fp::from(e))) - .to_vec(); - let shuffle_1 = [40, 10, 10, 20] - .map(|e: u64| Value::known(Fp::from(e))) - .to_vec(); - let circuit = MyCircuit { - input_0, - input_1, - shuffle_0, - shuffle_1, - }; - let prover = MockProver::run(K, &circuit, vec![]).unwrap(); - prover.assert_satisfied(); - test_prover::(K, circuit, true) - }, - "bf0868d8eb50e3ea00aee981070b8ebf551f24b24792f6157048f605e4c8cf12", + || test_prover(K, circuit, true), + "c8d44278f8b6ed8e15c9bb34c81a1d634398152d3a09a6589acb65d806a33b0d", ); } diff --git a/halo2_proofs/tests/vector-ops-unblinded.rs b/halo2_proofs/tests/vector-ops-unblinded.rs index 38461a1924..2ede2017c0 100644 --- a/halo2_proofs/tests/vector-ops-unblinded.rs +++ b/halo2_proofs/tests/vector-ops-unblinded.rs @@ -3,18 +3,16 @@ /// This is a simple example of how to use unblinded inputs to match up circuits that might be proved on different host machines. use std::marker::PhantomData; -use ff::FromUniformBytes; use halo2_debug::test_rng; use halo2_proofs::{ - arithmetic::{CurveAffine, Field}, + arithmetic::Field, circuit::{AssignedCell, Chip, Layouter, Region, SimpleFloorPlanner, Value}, plonk::*, poly::{ - commitment::ParamsProver, - ipa::{ - commitment::{IPACommitmentScheme, ParamsIPA}, - multiopen::{ProverIPA, VerifierIPA}, - strategy::AccumulatorStrategy, + kzg::{ + commitment::{KZGCommitmentScheme, ParamsKZG}, + multiopen::{ProverSHPLONK, VerifierSHPLONK}, + strategy::SingleStrategy, }, Rotation, }, @@ -22,6 +20,7 @@ use halo2_proofs::{ Blake2bRead, Blake2bWrite, Challenge255, TranscriptReadBuffer, TranscriptWriterBuffer, }, }; +use halo2curves::bn256::{Bn256, Fr, G1Affine}; // ANCHOR: instructions trait NumericInstructions: Chip { @@ -466,48 +465,42 @@ impl Circuit for AddCircuit { } // ANCHOR_END: circuit -fn test_prover( - k: u32, - circuit: impl Circuit, - expected: bool, - instances: Vec, -) -> Vec -where - C::Scalar: FromUniformBytes<64>, -{ - let rng = test_rng(); - - let params = ParamsIPA::::new(k); - let vk = keygen_vk(¶ms, &circuit).unwrap(); - let pk = keygen_pk(¶ms, vk, &circuit).unwrap(); - - let instances = vec![vec![instances]]; - let proof = { - let mut transcript = Blake2bWrite::<_, _, Challenge255<_>>::init(vec![]); - - create_proof::, ProverIPA, _, _, _, _>( - ¶ms, - &pk, - &[circuit], - &instances, - rng, - &mut transcript, - ) - .expect("proof generation should not fail"); - - transcript.finalize() - }; - - let accepted = { - let mut transcript = Blake2bRead::<_, _, Challenge255<_>>::init(&proof[..]); - - verify_proof_multi::, VerifierIPA, _, _, AccumulatorStrategy<_>>( - ¶ms, - pk.get_vk(), - &instances, - &mut transcript, - ) - }; +fn test_prover(k: u32, circuit: impl Circuit, expected: bool, instances: Vec) -> Vec { + // Setup + let mut rng = test_rng(); + let params = ParamsKZG::::setup(k, &mut rng); + let vk = keygen_vk(¶ms, &circuit).expect("keygen_vk should not fail"); + let pk = keygen_pk(¶ms, vk.clone(), &circuit).expect("keygen_pk should not fail"); + + let mut transcript = Blake2bWrite::<_, G1Affine, Challenge255<_>>::init(vec![]); + create_proof::, ProverSHPLONK<'_, Bn256>, _, _, _, _>( + ¶ms, + &pk, + &[circuit], + &[vec![instances.clone()]], + &mut rng, + &mut transcript, + ) + .expect("proof generation should not fail"); + let proof = transcript.finalize(); + + // Verify + let mut verifier_transcript = + Blake2bRead::<_, G1Affine, Challenge255<_>>::init(proof.as_slice()); + let verifier_params = params.verifier_params(); + + let accepted = verify_proof_multi::< + KZGCommitmentScheme, + VerifierSHPLONK, + _, + _, + SingleStrategy<_>, + >( + &verifier_params, + &vk, + &[vec![instances]], + &mut verifier_transcript, + ); assert_eq!(accepted, expected); @@ -516,8 +509,6 @@ where #[test] fn test_vector_ops_unbinded() { - use halo2curves::pasta::Fp; - const N: usize = 10; // ANCHOR: test-circuit // The number of rows in our circuit cannot exceed 2^k. Since our example @@ -525,10 +516,10 @@ fn test_vector_ops_unbinded() { let k = 7; // Prepare the inputs to the circuit! - let a = [Fp::from(2); N]; - let b = [Fp::from(3); N]; - let c_mul: Vec = a.iter().zip(b).map(|(&a, b)| a * b).collect(); - let c_add: Vec = a.iter().zip(b).map(|(&a, b)| a + b).collect(); + let a = [Fr::from(2); N]; + let b = [Fr::from(3); N]; + let c_mul: Vec = a.iter().zip(b).map(|(&a, b)| a * b).collect(); + let c_add: Vec = a.iter().zip(b).map(|(&a, b)| a + b).collect(); // Instantiate the mul circuit with the inputs. let mul_circuit = MulCircuit { @@ -544,14 +535,14 @@ fn test_vector_ops_unbinded() { // the commitments will be the first columns of the proof transcript so we can compare them easily let proof_1 = halo2_debug::test_result( - || test_prover::(k, mul_circuit.clone(), true, c_mul.clone()), - "8fb24ffebec78e9667e9f9eab6b4b8974d95b5db9023ef78788a08b3daf4b138", + || test_prover(k, mul_circuit.clone(), true, c_mul.clone()), + "1d0e66c45ff1868d2fa3de6cc4b7aa0f8c9d761929ed26c1307251a33f9c5950", ); // the commitments will be the first columns of the proof transcript so we can compare them easily let proof_2 = halo2_debug::test_result( - || test_prover::(k, add_circuit.clone(), true, c_add.clone()), - "ded7a6e1f2463fc1bc40311d409af170d57b3e32fe8d60f53403043ae718f4f9", + || test_prover(k, add_circuit.clone(), true, c_add.clone()), + "4d64c68078008db27906a54ecb25fb8f8b41d85850aeb2db136072baff266f3e", ); // the commitments will be the first columns of the proof transcript so we can compare them easily