diff --git a/CHANGELOG.md b/CHANGELOG.md index b6bfc521..9203dcd4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,8 +4,13 @@ ### Breaking changes +- [\#82](https://github.com/arkworks-rs/poly-commit/pull/82) Function parameter `opening_challenge: F` for `open`, + `check`, has been changed from `F` to `opening_challenges: &mut ChallengeGenerator`. + ### Features +- [\#82](https://github.com/arkworks-rs/poly-commit/pull/82) Add multivariate opening challenge strategy. Integrate with sponge API. + ### Improvements ### Bug fixes diff --git a/Cargo.toml b/Cargo.toml index e606cd1b..b4805c12 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,6 +25,7 @@ ark-serialize = { version = "^0.3.0", default-features = false, features = [ "de ark-ff = { version = "^0.3.0", default-features = false } ark-ec = { version = "^0.3.0", default-features = false } ark-poly = {version = "^0.3.0", default-features = false } +ark-sponge = {version = "^0.3.0", default-features = false} ark-std = { version = "^0.3.0", default-features = false } ark-relations = { version = "^0.3.0", default-features = false, optional = true } @@ -36,8 +37,6 @@ digest = "0.9" rayon = { version = "1", optional = true } derivative = { version = "2", features = [ "use_core" ] } -tracing = { version = "0.1", default-features = false, features = [ "attributes" ] } - [dev-dependencies] ark-ed-on-bls12-381 = { version = "^0.3.0", default-features = false } ark-bls12-381 = { version = "^0.3.0", default-features = false, features = [ "curve" ] } @@ -58,7 +57,7 @@ debug = true [features] default = [ "std", "parallel" ] -std = [ "ark-ff/std", "ark-ec/std", "ark-nonnative-field/std", "ark-poly/std", "ark-std/std", "ark-relations/std", "ark-serialize/std" ] -r1cs = [ "ark-relations", "ark-r1cs-std", "ark-nonnative-field", "hashbrown" ] +std = [ "ark-ff/std", "ark-ec/std", "ark-nonnative-field/std", "ark-poly/std", "ark-std/std", "ark-relations/std", "ark-serialize/std", "ark-sponge/std"] +r1cs = [ "ark-relations", "ark-r1cs-std", "ark-nonnative-field", "hashbrown", "ark-sponge/r1cs"] print-trace = [ "ark-std/print-trace" ] parallel = [ "std", "ark-ff/parallel", "ark-ec/parallel", "ark-poly/parallel", "ark-std/parallel", "rayon" ] diff --git a/src/challenge.rs b/src/challenge.rs new file mode 100644 index 00000000..aa78d902 --- /dev/null +++ b/src/challenge.rs @@ -0,0 +1,61 @@ +use ark_ff::PrimeField; +use ark_sponge::{CryptographicSponge, FieldElementSize}; + +/// `ChallengeGenerator` generates opening challenges using multivariate or univariate strategy. +/// For multivariate strategy, each challenge is freshly squeezed from a sponge. +/// For univariate strategy, each challenge is a power of one squeezed element from sponge. +/// +/// Note that mutable reference cannot be cloned. +#[derive(Clone)] +pub enum ChallengeGenerator { + /// Each challenge is freshly squeezed from a sponge. + Multivariate(S), + /// Each challenge is a power of one squeezed element from sponge. + /// + /// `Univariate(generator, next_element)` + Univariate(F, F), +} + +impl ChallengeGenerator { + /// Returns a challenge generator with multivariate strategy. Each challenge is freshly squeezed + /// from a sponge. + pub fn new_multivariate(sponge: S) -> Self { + Self::Multivariate(sponge) + } + + /// Returns a challenge generator with univariate strategy. Each challenge is a power of one + /// squeezed element from sponge. + pub fn new_univariate(sponge: &mut S) -> Self { + let gen = sponge.squeeze_field_elements(1)[0]; + Self::Univariate(gen, gen) + } + + /// Returns a challenge of size `size`. + /// * If `self == Self::Multivariate(...)`, then this squeezes out a challenge of size `size`. + /// * If `self == Self::Univariate(...)`, then this ignores the `size` argument and simply squeezes out + /// the next field element. + pub fn try_next_challenge_of_size(&mut self, size: FieldElementSize) -> F { + match self { + // multivariate (full) + Self::Multivariate(sponge) => sponge.squeeze_field_elements_with_sizes(&[size])[0], + // univariate + Self::Univariate(gen, next) => { + let result = next.clone(); + *next *= *gen; + result + } + } + } + /// Returns the next challenge generated. + pub fn next_challenge(&mut self) -> F { + self.try_next_challenge_of_size(FieldElementSize::Full) + } + + /// Returns the sponge state if `self` is multivariate. Returns `None` otherwise. + pub fn into_sponge(self) -> Option { + match self { + Self::Multivariate(s) => Some(s), + _ => None, + } + } +} diff --git a/src/constraints.rs b/src/constraints.rs index 41fe3582..5576d3e1 100644 --- a/src/constraints.rs +++ b/src/constraints.rs @@ -7,6 +7,7 @@ use ark_nonnative_field::NonNativeFieldVar; use ark_poly::Polynomial; use ark_r1cs_std::{fields::fp::FpVar, prelude::*}; use ark_relations::r1cs::{ConstraintSystemRef, Namespace, Result as R1CSResult, SynthesisError}; +use ark_sponge::CryptographicSponge; use ark_std::{borrow::Borrow, cmp::Eq, cmp::PartialEq, hash::Hash, marker::Sized}; use hashbrown::{HashMap, HashSet}; @@ -93,8 +94,9 @@ pub struct PCCheckRandomDataVar pub trait PCCheckVar< PCF: PrimeField, P: Polynomial, - PC: PolynomialCommitment, + PC: PolynomialCommitment, ConstraintF: PrimeField, + S: CryptographicSponge, >: Clone { /// An allocated version of `PC::VerifierKey`. @@ -117,7 +119,7 @@ pub trait PCCheckVar< type ProofVar: AllocVar + Clone; /// An allocated version of `PC::BatchLCProof`. - type BatchLCProofVar: AllocVar, ConstraintF> + Clone; + type BatchLCProofVar: AllocVar, ConstraintF> + Clone; /// Add to `ConstraintSystemRef` new constraints that check that `proof_i` is a valid evaluation /// proof at `point_i` for the polynomial in `commitment_i`. diff --git a/src/data_structures.rs b/src/data_structures.rs index e07c2e6a..ccf75874 100644 --- a/src/data_structures.rs +++ b/src/data_structures.rs @@ -1,5 +1,5 @@ -use crate::{Polynomial, PolynomialCommitment, Rc, String, Vec}; -use ark_ff::{Field, ToConstraintField}; +use crate::{Polynomial, Rc, String, Vec}; +use ark_ff::{Field, PrimeField, ToConstraintField}; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, SerializationError}; use ark_std::rand::RngCore; use ark_std::{ @@ -104,9 +104,9 @@ pub trait PCProof: Clone + ark_ff::ToBytes + CanonicalSerialize + CanonicalDeser /// A proof of satisfaction of linear combinations. #[derive(Clone, CanonicalSerialize, CanonicalDeserialize)] -pub struct BatchLCProof, PC: PolynomialCommitment> { +pub struct BatchLCProof { /// Evaluation proof. - pub proof: PC::BatchProof, + pub proof: T, /// Evaluations required to verify the proof. pub evals: Option>, } diff --git a/src/ipa_pc/mod.rs b/src/ipa_pc/mod.rs index 03ca3f8c..fb9cc385 100644 --- a/src/ipa_pc/mod.rs +++ b/src/ipa_pc/mod.rs @@ -1,4 +1,4 @@ -use crate::{BTreeMap, BTreeSet, String, ToString, Vec}; +use crate::{BTreeMap, BTreeSet, String, ToString, Vec, CHALLENGE_SIZE}; use crate::{BatchLCProof, Error, Evaluations, QuerySet, UVPolynomial}; use crate::{LabeledCommitment, LabeledPolynomial, LinearCombination}; use crate::{PCCommitterKey, PCRandomness, PCUniversalParams, PolynomialCommitment}; @@ -14,6 +14,8 @@ pub use data_structures::*; #[cfg(feature = "parallel")] use rayon::prelude::*; +use crate::challenge::ChallengeGenerator; +use ark_sponge::CryptographicSponge; use digest::Digest; /// A polynomial commitment scheme based on the hardness of the @@ -29,13 +31,25 @@ use digest::Digest; /// /// [pcdas]: https://eprint.iacr.org/2020/499 /// [marlin]: https://eprint.iacr.org/2019/1047 -pub struct InnerProductArgPC> { +pub struct InnerProductArgPC< + G: AffineCurve, + D: Digest, + P: UVPolynomial, + S: CryptographicSponge, +> { _projective: PhantomData, _digest: PhantomData, _poly: PhantomData

, + _sponge: PhantomData, } -impl> InnerProductArgPC { +impl InnerProductArgPC +where + G: AffineCurve, + D: Digest, + P: UVPolynomial, + S: CryptographicSponge, +{ /// `PROTOCOL_NAME` is used as a seed for the setup function. pub const PROTOCOL_NAME: &'static [u8] = b"PC-DL-2020"; @@ -88,7 +102,7 @@ impl> InnerProductArg point: G::ScalarField, values: impl IntoIterator, proof: &Proof, - opening_challenges: &dyn Fn(u64) -> G::ScalarField, + opening_challenges: &mut ChallengeGenerator, ) -> Option> { let check_time = start_timer!(|| "Succinct checking"); @@ -100,9 +114,7 @@ impl> InnerProductArg let mut combined_commitment_proj = G::Projective::zero(); let mut combined_v = G::ScalarField::zero(); - let mut opening_challenge_counter = 0; - let mut cur_challenge = opening_challenges(opening_challenge_counter); - opening_challenge_counter += 1; + let mut cur_challenge = opening_challenges.try_next_challenge_of_size(CHALLENGE_SIZE); let labeled_commitments = commitments.into_iter(); let values = values.into_iter(); @@ -111,8 +123,7 @@ impl> InnerProductArg let commitment = labeled_commitment.commitment(); combined_v += &(cur_challenge * &value); combined_commitment_proj += &labeled_commitment.commitment().comm.mul(cur_challenge); - cur_challenge = opening_challenges(opening_challenge_counter); - opening_challenge_counter += 1; + cur_challenge = opening_challenges.try_next_challenge_of_size(CHALLENGE_SIZE); let degree_bound = labeled_commitment.degree_bound(); assert_eq!(degree_bound.is_some(), commitment.shifted_comm.is_some()); @@ -123,8 +134,7 @@ impl> InnerProductArg combined_commitment_proj += &commitment.shifted_comm.unwrap().mul(cur_challenge); } - cur_challenge = opening_challenges(opening_challenge_counter); - opening_challenge_counter += 1; + cur_challenge = opening_challenges.try_next_challenge_of_size(CHALLENGE_SIZE); } let mut combined_commitment = combined_commitment_proj.into_affine(); @@ -302,11 +312,12 @@ impl> InnerProductArg } } -impl PolynomialCommitment for InnerProductArgPC +impl PolynomialCommitment for InnerProductArgPC where G: AffineCurve, D: Digest, P: UVPolynomial, + S: CryptographicSponge, { type UniversalParams = UniversalParams; type CommitterKey = CommitterKey; @@ -450,12 +461,12 @@ where Ok((comms, rands)) } - fn open_individual_opening_challenges<'a>( + fn open<'a>( ck: &Self::CommitterKey, labeled_polynomials: impl IntoIterator>, commitments: impl IntoIterator>, point: &'a P::Point, - opening_challenges: &dyn Fn(u64) -> G::ScalarField, + opening_challenges: &mut ChallengeGenerator, rands: impl IntoIterator, rng: Option<&mut dyn RngCore>, ) -> Result @@ -476,9 +487,7 @@ where let combine_time = start_timer!(|| "Combining polynomials, randomness, and commitments."); - let mut opening_challenge_counter = 0; - let mut cur_challenge = opening_challenges(opening_challenge_counter); - opening_challenge_counter += 1; + let mut cur_challenge = opening_challenges.try_next_challenge_of_size(CHALLENGE_SIZE); for (labeled_polynomial, (labeled_commitment, randomness)) in polys_iter.zip(comms_iter.zip(rands_iter)) @@ -500,8 +509,7 @@ where combined_rand += &(cur_challenge * &randomness.rand); } - cur_challenge = opening_challenges(opening_challenge_counter); - opening_challenge_counter += 1; + cur_challenge = opening_challenges.try_next_challenge_of_size(CHALLENGE_SIZE); let has_degree_bound = degree_bound.is_some(); @@ -534,8 +542,7 @@ where } } - cur_challenge = opening_challenges(opening_challenge_counter); - opening_challenge_counter += 1; + cur_challenge = opening_challenges.try_next_challenge_of_size(CHALLENGE_SIZE); } end_timer!(combine_time); @@ -694,13 +701,13 @@ where }) } - fn check_individual_opening_challenges<'a>( + fn check<'a>( vk: &Self::VerifierKey, commitments: impl IntoIterator>, point: &'a P::Point, values: impl IntoIterator, proof: &Self::Proof, - opening_challenges: &dyn Fn(u64) -> G::ScalarField, + opening_challenges: &mut ChallengeGenerator, _rng: Option<&mut dyn RngCore>, ) -> Result where @@ -745,13 +752,13 @@ where Ok(true) } - fn batch_check_individual_opening_challenges<'a, R: RngCore>( + fn batch_check<'a, R: RngCore>( vk: &Self::VerifierKey, commitments: impl IntoIterator>, query_set: &QuerySet, values: &Evaluations, proof: &Self::BatchProof, - opening_challenges: &dyn Fn(u64) -> G::ScalarField, + opening_challenges: &mut ChallengeGenerator, rng: &mut R, ) -> Result where @@ -831,16 +838,16 @@ where Ok(true) } - fn open_combinations_individual_opening_challenges<'a>( + fn open_combinations<'a>( ck: &Self::CommitterKey, - lc_s: impl IntoIterator>, + linear_combinations: impl IntoIterator>, polynomials: impl IntoIterator>, commitments: impl IntoIterator>, query_set: &QuerySet, - opening_challenges: &dyn Fn(u64) -> G::ScalarField, + opening_challenges: &mut ChallengeGenerator, rands: impl IntoIterator, rng: Option<&mut dyn RngCore>, - ) -> Result, Self::Error> + ) -> Result, Self::Error> where Self::Randomness: 'a, Self::Commitment: 'a, @@ -858,7 +865,7 @@ where let mut lc_commitments = Vec::new(); let mut lc_info = Vec::new(); - for lc in lc_s { + for lc in linear_combinations { let lc_label = lc.label().clone(); let mut poly = P::zero(); let mut degree_bound = None; @@ -927,7 +934,7 @@ where let lc_commitments = Self::construct_labeled_commitments(&lc_info, &lc_commitments); - let proof = Self::batch_open_individual_opening_challenges( + let proof = Self::batch_open( ck, lc_polynomials.iter(), lc_commitments.iter(), @@ -941,14 +948,14 @@ where /// Checks that `values` are the true evaluations at `query_set` of the polynomials /// committed in `labeled_commitments`. - fn check_combinations_individual_opening_challenges<'a, R: RngCore>( + fn check_combinations<'a, R: RngCore>( vk: &Self::VerifierKey, - lc_s: impl IntoIterator>, + linear_combinations: impl IntoIterator>, commitments: impl IntoIterator>, - query_set: &QuerySet, - evaluations: &Evaluations, - proof: &BatchLCProof, - opening_challenges: &dyn Fn(u64) -> G::ScalarField, + eqn_query_set: &QuerySet, + eqn_evaluations: &Evaluations, + proof: &BatchLCProof, + opening_challenges: &mut ChallengeGenerator, rng: &mut R, ) -> Result where @@ -962,8 +969,8 @@ where let mut lc_commitments = Vec::new(); let mut lc_info = Vec::new(); - let mut evaluations = evaluations.clone(); - for lc in lc_s { + let mut evaluations = eqn_evaluations.clone(); + for lc in linear_combinations { let lc_label = lc.label().clone(); let num_polys = lc.len(); @@ -1015,10 +1022,10 @@ where let lc_commitments = Self::construct_labeled_commitments(&lc_info, &lc_commitments); - Self::batch_check_individual_opening_challenges( + Self::batch_check( vk, &lc_commitments, - &query_set, + &eqn_query_set, &evaluations, proof, opening_challenges, @@ -1032,15 +1039,18 @@ mod tests { #![allow(non_camel_case_types)] use super::InnerProductArgPC; + use ark_ec::AffineCurve; use ark_ed_on_bls12_381::{EdwardsAffine, Fr}; use ark_ff::PrimeField; use ark_poly::{univariate::DensePolynomial as DensePoly, UVPolynomial}; + use ark_sponge::poseidon::PoseidonSponge; use ark_std::rand::rngs::StdRng; use blake2::Blake2s; type UniPoly = DensePoly; - type PC = InnerProductArgPC; - type PC_JJB2S = PC; + type Sponge = PoseidonSponge<::ScalarField>; + type PC = InnerProductArgPC; + type PC_JJB2S = PC; fn rand_poly(degree: usize, _: Option, rng: &mut StdRng) -> DensePoly { DensePoly::rand(degree, rng) @@ -1057,23 +1067,34 @@ mod tests { #[test] fn single_poly_test() { use crate::tests::*; - single_poly_test::<_, _, PC_JJB2S>(None, rand_poly::, rand_point::) - .expect("test failed for ed_on_bls12_381-blake2s"); + single_poly_test::<_, _, PC_JJB2S, _>( + None, + rand_poly::, + rand_point::, + poseidon_sponge_for_test, + ) + .expect("test failed for ed_on_bls12_381-blake2s"); } #[test] fn constant_poly_test() { use crate::tests::*; - single_poly_test::<_, _, PC_JJB2S>(None, constant_poly::, rand_point::) - .expect("test failed for ed_on_bls12_381-blake2s"); + single_poly_test::<_, _, PC_JJB2S, _>( + None, + constant_poly::, + rand_point::, + poseidon_sponge_for_test, + ) + .expect("test failed for ed_on_bls12_381-blake2s"); } #[test] fn quadratic_poly_degree_bound_multiple_queries_test() { use crate::tests::*; - quadratic_poly_degree_bound_multiple_queries_test::<_, _, PC_JJB2S>( + quadratic_poly_degree_bound_multiple_queries_test::<_, _, PC_JJB2S, _>( rand_poly::, rand_point::, + poseidon_sponge_for_test, ) .expect("test failed for ed_on_bls12_381-blake2s"); } @@ -1081,23 +1102,32 @@ mod tests { #[test] fn linear_poly_degree_bound_test() { use crate::tests::*; - linear_poly_degree_bound_test::<_, _, PC_JJB2S>(rand_poly::, rand_point::) - .expect("test failed for ed_on_bls12_381-blake2s"); + linear_poly_degree_bound_test::<_, _, PC_JJB2S, _>( + rand_poly::, + rand_point::, + poseidon_sponge_for_test, + ) + .expect("test failed for ed_on_bls12_381-blake2s"); } #[test] fn single_poly_degree_bound_test() { use crate::tests::*; - single_poly_degree_bound_test::<_, _, PC_JJB2S>(rand_poly::, rand_point::) - .expect("test failed for ed_on_bls12_381-blake2s"); + single_poly_degree_bound_test::<_, _, PC_JJB2S, _>( + rand_poly::, + rand_point::, + poseidon_sponge_for_test, + ) + .expect("test failed for ed_on_bls12_381-blake2s"); } #[test] fn single_poly_degree_bound_multiple_queries_test() { use crate::tests::*; - single_poly_degree_bound_multiple_queries_test::<_, _, PC_JJB2S>( + single_poly_degree_bound_multiple_queries_test::<_, _, PC_JJB2S, _>( rand_poly::, rand_point::, + poseidon_sponge_for_test, ) .expect("test failed for ed_on_bls12_381-blake2s"); } @@ -1105,9 +1135,10 @@ mod tests { #[test] fn two_polys_degree_bound_single_query_test() { use crate::tests::*; - two_polys_degree_bound_single_query_test::<_, _, PC_JJB2S>( + two_polys_degree_bound_single_query_test::<_, _, PC_JJB2S, _>( rand_poly::, rand_point::, + poseidon_sponge_for_test, ) .expect("test failed for ed_on_bls12_381-blake2s"); } @@ -1115,40 +1146,64 @@ mod tests { #[test] fn full_end_to_end_test() { use crate::tests::*; - full_end_to_end_test::<_, _, PC_JJB2S>(None, rand_poly::, rand_point::) - .expect("test failed for ed_on_bls12_381-blake2s"); + full_end_to_end_test::<_, _, PC_JJB2S, _>( + None, + rand_poly::, + rand_point::, + poseidon_sponge_for_test, + ) + .expect("test failed for ed_on_bls12_381-blake2s"); println!("Finished ed_on_bls12_381-blake2s"); } #[test] fn single_equation_test() { use crate::tests::*; - single_equation_test::<_, _, PC_JJB2S>(None, rand_poly::, rand_point::) - .expect("test failed for ed_on_bls12_381-blake2s"); + single_equation_test::<_, _, PC_JJB2S, _>( + None, + rand_poly::, + rand_point::, + poseidon_sponge_for_test, + ) + .expect("test failed for ed_on_bls12_381-blake2s"); println!("Finished ed_on_bls12_381-blake2s"); } #[test] fn two_equation_test() { use crate::tests::*; - two_equation_test::<_, _, PC_JJB2S>(None, rand_poly::, rand_point::) - .expect("test failed for ed_on_bls12_381-blake2s"); + two_equation_test::<_, _, PC_JJB2S, _>( + None, + rand_poly::, + rand_point::, + poseidon_sponge_for_test, + ) + .expect("test failed for ed_on_bls12_381-blake2s"); println!("Finished ed_on_bls12_381-blake2s"); } #[test] fn two_equation_degree_bound_test() { use crate::tests::*; - two_equation_degree_bound_test::<_, _, PC_JJB2S>(rand_poly::, rand_point::) - .expect("test failed for ed_on_bls12_381-blake2s"); + two_equation_degree_bound_test::<_, _, PC_JJB2S, _>( + rand_poly::, + rand_point::, + poseidon_sponge_for_test, + ) + .expect("test failed for ed_on_bls12_381-blake2s"); println!("Finished ed_on_bls12_381-blake2s"); } #[test] fn full_end_to_end_equation_test() { use crate::tests::*; - full_end_to_end_equation_test::<_, _, PC_JJB2S>(None, rand_poly::, rand_point::) - .expect("test failed for ed_on_bls12_381-blake2s"); + full_end_to_end_equation_test::<_, _, PC_JJB2S, _>( + None, + rand_poly::, + rand_point::, + poseidon_sponge_for_test, + ) + .expect("test failed for ed_on_bls12_381-blake2s"); println!("Finished ed_on_bls12_381-blake2s"); } @@ -1156,8 +1211,12 @@ mod tests { #[should_panic] fn bad_degree_bound_test() { use crate::tests::*; - bad_degree_bound_test::<_, _, PC_JJB2S>(rand_poly::, rand_point::) - .expect("test failed for ed_on_bls12_381-blake2s"); + bad_degree_bound_test::<_, _, PC_JJB2S, _>( + rand_poly::, + rand_point::, + poseidon_sponge_for_test, + ) + .expect("test failed for ed_on_bls12_381-blake2s"); println!("Finished ed_on_bls12_381-blake2s"); } } diff --git a/src/lib.rs b/src/lib.rs index 2f8fcf92..0107c1e9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,12 +10,13 @@ #![deny(unused_comparisons, bare_trait_objects, unused_must_use, const_err)] #![forbid(unsafe_code)] +#[allow(unused)] #[macro_use] extern crate derivative; #[macro_use] extern crate ark_std; -use ark_ff::Field; +use ark_ff::{Field, PrimeField}; pub use ark_poly::{Polynomial, UVPolynomial}; use ark_std::rand::RngCore; @@ -97,6 +98,8 @@ pub mod sonic_pc; /// [pcdas]: https://eprint.iacr.org/2020/499 pub mod ipa_pc; +/// Defines the challenge strategies and challenge generator. +pub mod challenge; /// A multilinear polynomial commitment scheme that converts n-variate multilinear polynomial into /// n quotient UV polynomial. This scheme is based on hardness of the discrete logarithm /// in prime-order groups. Construction is detailed in [[XZZPD19]][xzzpd19] and [[ZGKPP18]][zgkpp18] @@ -105,6 +108,8 @@ pub mod ipa_pc; /// [zgkpp]: https://ieeexplore.ieee.org/document/8418645 pub mod multilinear_pc; +use crate::challenge::ChallengeGenerator; +use ark_sponge::{CryptographicSponge, FieldElementSize}; /// Multivariate polynomial commitment based on the construction in /// [[PST13]][pst] with batching and (optional) hiding property inspired /// by the univariate scheme in [[CHMMVW20, "Marlin"]][marlin] @@ -130,7 +135,9 @@ pub type Evaluations = BTreeMap<(String, T), F>; /// a sender to commit to multiple polynomials and later provide a succinct proof /// of evaluation for the corresponding commitments at a query set `Q`, while /// enforcing per-polynomial degree bounds. -pub trait PolynomialCommitment>: Sized { +pub trait PolynomialCommitment, S: CryptographicSponge>: + Sized +{ /// The universal parameters for the commitment scheme. These are "trimmed" /// down to `Self::CommitterKey` and `Self::VerifierKey` by `Self::trim`. type UniversalParams: PCUniversalParams; @@ -199,180 +206,13 @@ pub trait PolynomialCommitment>: Sized { where P: 'a; - /// On input a list of labeled polynomials and a query point, `open` outputs a proof of evaluation - /// of the polynomials at the query point. - fn open<'a>( - ck: &Self::CommitterKey, - labeled_polynomials: impl IntoIterator>, - commitments: impl IntoIterator>, - point: &'a P::Point, - opening_challenge: F, - rands: impl IntoIterator, - rng: Option<&mut dyn RngCore>, - ) -> Result - where - P: 'a, - Self::Randomness: 'a, - Self::Commitment: 'a, - { - let opening_challenges = |pow| opening_challenge.pow(&[pow]); - Self::open_individual_opening_challenges( - ck, - labeled_polynomials, - commitments, - point, - &opening_challenges, - rands, - rng, - ) - } - - /// On input a list of labeled polynomials and a query set, `open` outputs a proof of evaluation - /// of the polynomials at the points in the query set. - fn batch_open<'a>( - ck: &Self::CommitterKey, - labeled_polynomials: impl IntoIterator>, - commitments: impl IntoIterator>, - query_set: &QuerySet, - opening_challenge: F, - rands: impl IntoIterator, - rng: Option<&mut dyn RngCore>, - ) -> Result - where - Self::Randomness: 'a, - Self::Commitment: 'a, - P: 'a, - { - let opening_challenges = |pow| opening_challenge.pow(&[pow]); - Self::batch_open_individual_opening_challenges( - ck, - labeled_polynomials, - commitments, - query_set, - &opening_challenges, - rands, - rng, - ) - } - - /// Verifies that `values` are the evaluations at `point` of the polynomials - /// committed inside `commitments`. - fn check<'a>( - vk: &Self::VerifierKey, - commitments: impl IntoIterator>, - point: &'a P::Point, - values: impl IntoIterator, - proof: &Self::Proof, - opening_challenge: F, - rng: Option<&mut dyn RngCore>, - ) -> Result - where - Self::Commitment: 'a, - { - let opening_challenges = |pow| opening_challenge.pow(&[pow]); - Self::check_individual_opening_challenges( - vk, - commitments, - &point, - values, - proof, - &opening_challenges, - rng, - ) - } - - /// Checks that `values` are the true evaluations at `query_set` of the polynomials - /// committed in `labeled_commitments`. - fn batch_check<'a, R: RngCore>( - vk: &Self::VerifierKey, - commitments: impl IntoIterator>, - query_set: &QuerySet, - evaluations: &Evaluations, - proof: &Self::BatchProof, - opening_challenge: F, - rng: &mut R, - ) -> Result - where - Self::Commitment: 'a, - { - let opening_challenges = |pow| opening_challenge.pow(&[pow]); - Self::batch_check_individual_opening_challenges( - vk, - commitments, - query_set, - evaluations, - proof, - &opening_challenges, - rng, - ) - } - - /// On input a list of polynomials, linear combinations of those polynomials, - /// and a query set, `open_combination` outputs a proof of evaluation of - /// the combinations at the points in the query set. - fn open_combinations<'a>( - ck: &Self::CommitterKey, - linear_combinations: impl IntoIterator>, - polynomials: impl IntoIterator>, - commitments: impl IntoIterator>, - query_set: &QuerySet, - opening_challenge: F, - rands: impl IntoIterator, - rng: Option<&mut dyn RngCore>, - ) -> Result, Self::Error> - where - P: 'a, - Self::Randomness: 'a, - Self::Commitment: 'a, - { - let opening_challenges = |pow| opening_challenge.pow(&[pow]); - Self::open_combinations_individual_opening_challenges( - ck, - linear_combinations, - polynomials, - commitments, - query_set, - &opening_challenges, - rands, - rng, - ) - } - - /// Checks that `evaluations` are the true evaluations at `query_set` of the - /// linear combinations of polynomials committed in `commitments`. - fn check_combinations<'a, R: RngCore>( - vk: &Self::VerifierKey, - linear_combinations: impl IntoIterator>, - commitments: impl IntoIterator>, - eqn_query_set: &QuerySet, - eqn_evaluations: &Evaluations, - proof: &BatchLCProof, - opening_challenge: F, - rng: &mut R, - ) -> Result - where - Self::Commitment: 'a, - { - let opening_challenges = |pow| opening_challenge.pow(&[pow]); - Self::check_combinations_individual_opening_challenges( - vk, - linear_combinations, - commitments, - eqn_query_set, - eqn_evaluations, - proof, - &opening_challenges, - rng, - ) - } - /// open but with individual challenges - fn open_individual_opening_challenges<'a>( + fn open<'a>( ck: &Self::CommitterKey, labeled_polynomials: impl IntoIterator>, commitments: impl IntoIterator>, point: &'a P::Point, - opening_challenges: &dyn Fn(u64) -> F, + challenge_generator: &mut ChallengeGenerator, rands: impl IntoIterator, rng: Option<&mut dyn RngCore>, ) -> Result @@ -382,26 +222,26 @@ pub trait PolynomialCommitment>: Sized { Self::Commitment: 'a; /// check but with individual challenges - fn check_individual_opening_challenges<'a>( + fn check<'a>( vk: &Self::VerifierKey, commitments: impl IntoIterator>, point: &'a P::Point, values: impl IntoIterator, proof: &Self::Proof, - opening_challenges: &dyn Fn(u64) -> F, + challenge_generator: &mut ChallengeGenerator, rng: Option<&mut dyn RngCore>, ) -> Result where Self::Commitment: 'a; /// batch_check but with individual challenges - fn batch_check_individual_opening_challenges<'a, R: RngCore>( + fn batch_check<'a, R: RngCore>( vk: &Self::VerifierKey, commitments: impl IntoIterator>, query_set: &QuerySet, evaluations: &Evaluations, proof: &Self::BatchProof, - opening_challenges: &dyn Fn(u64) -> F, + challenge_generator: &mut ChallengeGenerator, rng: &mut R, ) -> Result where @@ -442,13 +282,13 @@ pub trait PolynomialCommitment>: Sized { } let proof_time = start_timer!(|| "Checking per-query proof"); - result &= Self::check_individual_opening_challenges( + result &= Self::check( vk, comms, &point, values, &proof, - opening_challenges, + challenge_generator, Some(rng), )?; end_timer!(proof_time); @@ -457,16 +297,16 @@ pub trait PolynomialCommitment>: Sized { } /// open_combinations but with individual challenges - fn open_combinations_individual_opening_challenges<'a>( + fn open_combinations<'a>( ck: &Self::CommitterKey, linear_combinations: impl IntoIterator>, polynomials: impl IntoIterator>, commitments: impl IntoIterator>, query_set: &QuerySet, - opening_challenges: &dyn Fn(u64) -> F, + challenge_generator: &mut ChallengeGenerator, rands: impl IntoIterator, rng: Option<&mut dyn RngCore>, - ) -> Result, Self::Error> + ) -> Result, Self::Error> where Self::Randomness: 'a, Self::Commitment: 'a, @@ -477,12 +317,12 @@ pub trait PolynomialCommitment>: Sized { let poly_query_set = lc_query_set_to_poly_query_set(linear_combinations.iter().copied(), query_set); let poly_evals = evaluate_query_set(polynomials.iter().copied(), &poly_query_set); - let proof = Self::batch_open_individual_opening_challenges( + let proof = Self::batch_open( ck, polynomials, commitments, &poly_query_set, - opening_challenges, + challenge_generator, rands, rng, )?; @@ -493,14 +333,14 @@ pub trait PolynomialCommitment>: Sized { } /// check_combinations with individual challenges - fn check_combinations_individual_opening_challenges<'a, R: RngCore>( + fn check_combinations<'a, R: RngCore>( vk: &Self::VerifierKey, linear_combinations: impl IntoIterator>, commitments: impl IntoIterator>, eqn_query_set: &QuerySet, eqn_evaluations: &Evaluations, - proof: &BatchLCProof, - opening_challenges: &dyn Fn(u64) -> F, + proof: &BatchLCProof, + challenge_generator: &mut ChallengeGenerator, rng: &mut R, ) -> Result where @@ -546,13 +386,13 @@ pub trait PolynomialCommitment>: Sized { } } - let pc_result = Self::batch_check_individual_opening_challenges( + let pc_result = Self::batch_check( vk, commitments, &poly_query_set, &poly_evals, proof, - opening_challenges, + challenge_generator, rng, )?; if !pc_result { @@ -564,12 +404,12 @@ pub trait PolynomialCommitment>: Sized { } /// batch_open with individual challenges - fn batch_open_individual_opening_challenges<'a>( + fn batch_open<'a>( ck: &Self::CommitterKey, labeled_polynomials: impl IntoIterator>, commitments: impl IntoIterator>, query_set: &QuerySet, - opening_challenges: &dyn Fn(u64) -> F, + challenge_generator: &mut ChallengeGenerator, rands: impl IntoIterator, rng: Option<&mut dyn RngCore>, ) -> Result @@ -619,12 +459,12 @@ pub trait PolynomialCommitment>: Sized { } let proof_time = start_timer!(|| "Creating proof"); - let proof = Self::open_individual_opening_challenges( + let proof = Self::open( ck, query_polys, query_comms, &point, - opening_challenges, + challenge_generator, query_rands, Some(rng), )?; @@ -639,6 +479,9 @@ pub trait PolynomialCommitment>: Sized { } } +/// The size of opening challenges in bits. +pub const CHALLENGE_SIZE: FieldElementSize = FieldElementSize::Truncated(128); + /// Evaluate the given polynomials at `query_set`. pub fn evaluate_query_set<'a, F, P, T>( polys: impl IntoIterator>, @@ -683,8 +526,8 @@ fn lc_query_set_to_poly_query_set<'a, F: Field, T: Clone + Ord>( #[cfg(test)] pub mod tests { use crate::*; - use ark_ff::Field; use ark_poly::Polynomial; + use ark_sponge::poseidon::{PoseidonParameters, PoseidonSponge}; use ark_std::rand::{ distributions::{Distribution, Uniform}, rngs::StdRng, @@ -692,7 +535,7 @@ pub mod tests { }; use ark_std::test_rng; - struct TestInfo> { + struct TestInfo, S: CryptographicSponge> { num_iters: usize, max_degree: Option, supported_degree: Option, @@ -703,102 +546,113 @@ pub mod tests { num_equations: Option, rand_poly: fn(usize, Option, &mut StdRng) -> P, rand_point: fn(Option, &mut StdRng) -> P::Point, + sponge: fn() -> S, } - pub fn bad_degree_bound_test( + pub fn bad_degree_bound_test( rand_poly: fn(usize, Option, &mut StdRng) -> P, rand_point: fn(Option, &mut StdRng) -> P::Point, + sponge: fn() -> S, ) -> Result<(), PC::Error> where - F: Field, + F: PrimeField, P: Polynomial, - PC: PolynomialCommitment, + PC: PolynomialCommitment, + S: CryptographicSponge, { - let rng = &mut test_rng(); - let max_degree = 100; - let pp = PC::setup(max_degree, None, rng)?; - for _ in 0..10 { - let supported_degree = Uniform::from(1..=max_degree).sample(rng); - assert!( - max_degree >= supported_degree, - "max_degree < supported_degree" - ); - - let mut labels = Vec::new(); - let mut polynomials = Vec::new(); - let mut degree_bounds = Vec::new(); - - for i in 0..10 { - let label = format!("Test{}", i); - labels.push(label.clone()); - let degree_bound = 1usize; - let hiding_bound = Some(1); - degree_bounds.push(degree_bound); - - polynomials.push(LabeledPolynomial::new( - label, - rand_poly(supported_degree, None, rng), - Some(degree_bound), - hiding_bound, - )); - } + let challenge_generators = vec![ + ChallengeGenerator::new_multivariate(sponge()), + ChallengeGenerator::new_univariate(&mut sponge()), + ]; + + for challenge_gen in challenge_generators { + let rng = &mut test_rng(); + let max_degree = 100; + let pp = PC::setup(max_degree, None, rng)?; + for _ in 0..10 { + let supported_degree = Uniform::from(1..=max_degree).sample(rng); + assert!( + max_degree >= supported_degree, + "max_degree < supported_degree" + ); - let supported_hiding_bound = polynomials - .iter() - .map(|p| p.hiding_bound().unwrap_or(0)) - .max() - .unwrap_or(0); - println!("supported degree: {:?}", supported_degree); - println!("supported hiding bound: {:?}", supported_hiding_bound); - let (ck, vk) = PC::trim( - &pp, - supported_degree, - supported_hiding_bound, - Some(degree_bounds.as_slice()), - )?; - println!("Trimmed"); + let mut labels = Vec::new(); + let mut polynomials = Vec::new(); + let mut degree_bounds = Vec::new(); + + for i in 0..10 { + let label = format!("Test{}", i); + labels.push(label.clone()); + let degree_bound = 1usize; + let hiding_bound = Some(1); + degree_bounds.push(degree_bound); + + polynomials.push(LabeledPolynomial::new( + label, + rand_poly(supported_degree, None, rng), + Some(degree_bound), + hiding_bound, + )); + } + + let supported_hiding_bound = polynomials + .iter() + .map(|p| p.hiding_bound().unwrap_or(0)) + .max() + .unwrap_or(0); + println!("supported degree: {:?}", supported_degree); + println!("supported hiding bound: {:?}", supported_hiding_bound); + let (ck, vk) = PC::trim( + &pp, + supported_degree, + supported_hiding_bound, + Some(degree_bounds.as_slice()), + )?; + println!("Trimmed"); - let (comms, rands) = PC::commit(&ck, &polynomials, Some(rng))?; + let (comms, rands) = PC::commit(&ck, &polynomials, Some(rng))?; - let mut query_set = QuerySet::new(); - let mut values = Evaluations::new(); - let point = rand_point(None, rng); - for (i, label) in labels.iter().enumerate() { - query_set.insert((label.clone(), (format!("{}", i), point.clone()))); - let value = polynomials[i].evaluate(&point); - values.insert((label.clone(), point.clone()), value); + let mut query_set = QuerySet::new(); + let mut values = Evaluations::new(); + let point = rand_point(None, rng); + for (i, label) in labels.iter().enumerate() { + query_set.insert((label.clone(), (format!("{}", i), point.clone()))); + let value = polynomials[i].evaluate(&point); + values.insert((label.clone(), point.clone()), value); + } + println!("Generated query set"); + + let proof = PC::batch_open( + &ck, + &polynomials, + &comms, + &query_set, + &mut (challenge_gen.clone()), + &rands, + Some(rng), + )?; + let result = PC::batch_check( + &vk, + &comms, + &query_set, + &values, + &proof, + &mut (challenge_gen.clone()), + rng, + )?; + assert!(result, "proof was incorrect, Query set: {:#?}", query_set); } - println!("Generated query set"); - - let opening_challenge = F::rand(rng); - let proof = PC::batch_open( - &ck, - &polynomials, - &comms, - &query_set, - opening_challenge, - &rands, - Some(rng), - )?; - let result = PC::batch_check( - &vk, - &comms, - &query_set, - &values, - &proof, - opening_challenge, - rng, - )?; - assert!(result, "proof was incorrect, Query set: {:#?}", query_set); } + Ok(()) } - fn test_template(info: TestInfo) -> Result<(), PC::Error> + fn test_template(info: TestInfo) -> Result<(), PC::Error> where - F: Field, + F: PrimeField, P: Polynomial, - PC: PolynomialCommitment, + PC: PolynomialCommitment, + S: CryptographicSponge, { let TestInfo { num_iters, @@ -811,131 +665,139 @@ pub mod tests { num_equations: _, rand_poly, rand_point, + sponge, } = info; - let rng = &mut test_rng(); - // If testing multivariate polynomials, make the max degree lower - let max_degree = match num_vars { - Some(_) => max_degree.unwrap_or(Uniform::from(2..=10).sample(rng)), - None => max_degree.unwrap_or(Uniform::from(2..=64).sample(rng)), - }; - let pp = PC::setup(max_degree, num_vars, rng)?; - - for _ in 0..num_iters { - let supported_degree = - supported_degree.unwrap_or(Uniform::from(1..=max_degree).sample(rng)); - assert!( - max_degree >= supported_degree, - "max_degree < supported_degree" - ); - let mut polynomials: Vec> = Vec::new(); - let mut degree_bounds = if enforce_degree_bounds { - Some(Vec::new()) - } else { - None + let challenge_gens = vec![ + ChallengeGenerator::new_multivariate(sponge()), + ChallengeGenerator::new_univariate(&mut sponge()), + ]; + + for challenge_gen in challenge_gens { + let rng = &mut test_rng(); + // If testing multivariate polynomials, make the max degree lower + let max_degree = match num_vars { + Some(_) => max_degree.unwrap_or(Uniform::from(2..=10).sample(rng)), + None => max_degree.unwrap_or(Uniform::from(2..=64).sample(rng)), }; - - let mut labels = Vec::new(); - println!("Sampled supported degree"); - - // Generate polynomials - let num_points_in_query_set = Uniform::from(1..=max_num_queries).sample(rng); - for i in 0..num_polynomials { - let label = format!("Test{}", i); - labels.push(label.clone()); - let degree = Uniform::from(1..=supported_degree).sample(rng); - let degree_bound = if let Some(degree_bounds) = &mut degree_bounds { - let range = Uniform::from(degree..=supported_degree); - let degree_bound = range.sample(rng); - degree_bounds.push(degree_bound); - Some(degree_bound) + let pp = PC::setup(max_degree, num_vars, rng)?; + + for _ in 0..num_iters { + let supported_degree = + supported_degree.unwrap_or(Uniform::from(1..=max_degree).sample(rng)); + assert!( + max_degree >= supported_degree, + "max_degree < supported_degree" + ); + let mut polynomials: Vec> = Vec::new(); + let mut degree_bounds = if enforce_degree_bounds { + Some(Vec::new()) } else { None }; - let hiding_bound = if num_points_in_query_set >= degree { - Some(degree) - } else { - Some(num_points_in_query_set) - }; + let mut labels = Vec::new(); + println!("Sampled supported degree"); - polynomials.push(LabeledPolynomial::new( - label, - rand_poly(degree, num_vars, rng).into(), - degree_bound, - hiding_bound, - )) - } - let supported_hiding_bound = polynomials - .iter() - .map(|p| p.hiding_bound().unwrap_or(0)) - .max() - .unwrap_or(0); - println!("supported degree: {:?}", supported_degree); - println!("supported hiding bound: {:?}", supported_hiding_bound); - println!("num_points_in_query_set: {:?}", num_points_in_query_set); - let (ck, vk) = PC::trim( - &pp, - supported_degree, - supported_hiding_bound, - degree_bounds.as_ref().map(|s| s.as_slice()), - )?; - println!("Trimmed"); + // Generate polynomials + let num_points_in_query_set = Uniform::from(1..=max_num_queries).sample(rng); + for i in 0..num_polynomials { + let label = format!("Test{}", i); + labels.push(label.clone()); + let degree = Uniform::from(1..=supported_degree).sample(rng); + let degree_bound = if let Some(degree_bounds) = &mut degree_bounds { + let range = Uniform::from(degree..=supported_degree); + let degree_bound = range.sample(rng); + degree_bounds.push(degree_bound); + Some(degree_bound) + } else { + None + }; - let (comms, rands) = PC::commit(&ck, &polynomials, Some(rng))?; + let hiding_bound = if num_points_in_query_set >= degree { + Some(degree) + } else { + Some(num_points_in_query_set) + }; - // Construct query set - let mut query_set = QuerySet::new(); - let mut values = Evaluations::new(); - for _ in 0..num_points_in_query_set { - let point = rand_point(num_vars, rng); - for (i, label) in labels.iter().enumerate() { - query_set.insert((label.clone(), (format!("{}", i), point.clone()))); - let value = polynomials[i].evaluate(&point); - values.insert((label.clone(), point.clone()), value); + polynomials.push(LabeledPolynomial::new( + label, + rand_poly(degree, num_vars, rng).into(), + degree_bound, + hiding_bound, + )) } - } - println!("Generated query set"); - - let opening_challenge = F::rand(rng); - let proof = PC::batch_open( - &ck, - &polynomials, - &comms, - &query_set, - opening_challenge, - &rands, - Some(rng), - )?; - let result = PC::batch_check( - &vk, - &comms, - &query_set, - &values, - &proof, - opening_challenge, - rng, - )?; - if !result { - println!( - "Failed with {} polynomials, num_points_in_query_set: {:?}", - num_polynomials, num_points_in_query_set - ); - println!("Degree of polynomials:",); - for poly in polynomials { - println!("Degree: {:?}", poly.degree()); + let supported_hiding_bound = polynomials + .iter() + .map(|p| p.hiding_bound().unwrap_or(0)) + .max() + .unwrap_or(0); + println!("supported degree: {:?}", supported_degree); + println!("supported hiding bound: {:?}", supported_hiding_bound); + println!("num_points_in_query_set: {:?}", num_points_in_query_set); + let (ck, vk) = PC::trim( + &pp, + supported_degree, + supported_hiding_bound, + degree_bounds.as_ref().map(|s| s.as_slice()), + )?; + println!("Trimmed"); + + let (comms, rands) = PC::commit(&ck, &polynomials, Some(rng))?; + + // Construct query set + let mut query_set = QuerySet::new(); + let mut values = Evaluations::new(); + for _ in 0..num_points_in_query_set { + let point = rand_point(num_vars, rng); + for (i, label) in labels.iter().enumerate() { + query_set.insert((label.clone(), (format!("{}", i), point.clone()))); + let value = polynomials[i].evaluate(&point); + values.insert((label.clone(), point.clone()), value); + } } + println!("Generated query set"); + + let proof = PC::batch_open( + &ck, + &polynomials, + &comms, + &query_set, + &mut (challenge_gen.clone()), + &rands, + Some(rng), + )?; + let result = PC::batch_check( + &vk, + &comms, + &query_set, + &values, + &proof, + &mut (challenge_gen.clone()), + rng, + )?; + if !result { + println!( + "Failed with {} polynomials, num_points_in_query_set: {:?}", + num_polynomials, num_points_in_query_set + ); + println!("Degree of polynomials:",); + for poly in polynomials { + println!("Degree: {:?}", poly.degree()); + } + } + assert!(result, "proof was incorrect, Query set: {:#?}", query_set); } - assert!(result, "proof was incorrect, Query set: {:#?}", query_set); } Ok(()) } - fn equation_test_template(info: TestInfo) -> Result<(), PC::Error> + fn equation_test_template(info: TestInfo) -> Result<(), PC::Error> where - F: Field, + F: PrimeField, P: Polynomial, - PC: PolynomialCommitment, + PC: PolynomialCommitment, + S: CryptographicSponge, { let TestInfo { num_iters, @@ -948,175 +810,184 @@ pub mod tests { num_equations, rand_poly, rand_point, + sponge, } = info; - let rng = &mut test_rng(); - // If testing multivariate polynomials, make the max degree lower - let max_degree = match num_vars { - Some(_) => max_degree.unwrap_or(Uniform::from(2..=10).sample(rng)), - None => max_degree.unwrap_or(Uniform::from(2..=64).sample(rng)), - }; - let pp = PC::setup(max_degree, num_vars, rng)?; - - for _ in 0..num_iters { - let supported_degree = - supported_degree.unwrap_or(Uniform::from(1..=max_degree).sample(rng)); - assert!( - max_degree >= supported_degree, - "max_degree < supported_degree" - ); - let mut polynomials = Vec::new(); - let mut degree_bounds = if enforce_degree_bounds { - Some(Vec::new()) - } else { - None + let challenge_gens = vec![ + ChallengeGenerator::new_multivariate(sponge()), + ChallengeGenerator::new_univariate(&mut sponge()), + ]; + + for challenge_gen in challenge_gens { + let rng = &mut test_rng(); + // If testing multivariate polynomials, make the max degree lower + let max_degree = match num_vars { + Some(_) => max_degree.unwrap_or(Uniform::from(2..=10).sample(rng)), + None => max_degree.unwrap_or(Uniform::from(2..=64).sample(rng)), }; - - let mut labels = Vec::new(); - println!("Sampled supported degree"); - - // Generate polynomials - let num_points_in_query_set = Uniform::from(1..=max_num_queries).sample(rng); - for i in 0..num_polynomials { - let label = format!("Test{}", i); - labels.push(label.clone()); - let degree = Uniform::from(1..=supported_degree).sample(rng); - let degree_bound = if let Some(degree_bounds) = &mut degree_bounds { - if rng.gen() { - let range = Uniform::from(degree..=supported_degree); - let degree_bound = range.sample(rng); - degree_bounds.push(degree_bound); - Some(degree_bound) - } else { - None - } + let pp = PC::setup(max_degree, num_vars, rng)?; + + for _ in 0..num_iters { + let supported_degree = + supported_degree.unwrap_or(Uniform::from(1..=max_degree).sample(rng)); + assert!( + max_degree >= supported_degree, + "max_degree < supported_degree" + ); + let mut polynomials = Vec::new(); + let mut degree_bounds = if enforce_degree_bounds { + Some(Vec::new()) } else { None }; - let hiding_bound = if num_points_in_query_set >= degree { - Some(degree) - } else { - Some(num_points_in_query_set) - }; - println!("Hiding bound: {:?}", hiding_bound); - - polynomials.push(LabeledPolynomial::new( - label, - rand_poly(degree, num_vars, rng), - degree_bound, - hiding_bound, - )) - } - println!("supported degree: {:?}", supported_degree); - println!("num_points_in_query_set: {:?}", num_points_in_query_set); - println!("{:?}", degree_bounds); - println!("{}", num_polynomials); - println!("{}", enforce_degree_bounds); - - let (ck, vk) = PC::trim( - &pp, - supported_degree, - supported_degree, - degree_bounds.as_ref().map(|s| s.as_slice()), - )?; - println!("Trimmed"); - - let (comms, rands) = PC::commit(&ck, &polynomials, Some(rng))?; - - // Let's construct our equations - let mut linear_combinations = Vec::new(); - let mut query_set = QuerySet::new(); - let mut values = Evaluations::new(); - for i in 0..num_points_in_query_set { - let point = rand_point(num_vars, rng); - for j in 0..num_equations.unwrap() { - let label = format!("query {} eqn {}", i, j); - let mut lc = LinearCombination::empty(label.clone()); - - let mut value = F::zero(); - let should_have_degree_bounds: bool = rng.gen(); - for (k, label) in labels.iter().enumerate() { - if should_have_degree_bounds { - value += &polynomials[k].evaluate(&point); - lc.push((F::one(), label.to_string().into())); - break; + let mut labels = Vec::new(); + println!("Sampled supported degree"); + + // Generate polynomials + let num_points_in_query_set = Uniform::from(1..=max_num_queries).sample(rng); + for i in 0..num_polynomials { + let label = format!("Test{}", i); + labels.push(label.clone()); + let degree = Uniform::from(1..=supported_degree).sample(rng); + let degree_bound = if let Some(degree_bounds) = &mut degree_bounds { + if rng.gen() { + let range = Uniform::from(degree..=supported_degree); + let degree_bound = range.sample(rng); + degree_bounds.push(degree_bound); + Some(degree_bound) } else { - let poly = &polynomials[k]; - if poly.degree_bound().is_some() { - continue; + None + } + } else { + None + }; + + let hiding_bound = if num_points_in_query_set >= degree { + Some(degree) + } else { + Some(num_points_in_query_set) + }; + println!("Hiding bound: {:?}", hiding_bound); + + polynomials.push(LabeledPolynomial::new( + label, + rand_poly(degree, num_vars, rng), + degree_bound, + hiding_bound, + )) + } + println!("supported degree: {:?}", supported_degree); + println!("num_points_in_query_set: {:?}", num_points_in_query_set); + println!("{:?}", degree_bounds); + println!("{}", num_polynomials); + println!("{}", enforce_degree_bounds); + + let (ck, vk) = PC::trim( + &pp, + supported_degree, + supported_degree, + degree_bounds.as_ref().map(|s| s.as_slice()), + )?; + println!("Trimmed"); + + let (comms, rands) = PC::commit(&ck, &polynomials, Some(rng))?; + + // Let's construct our equations + let mut linear_combinations = Vec::new(); + let mut query_set = QuerySet::new(); + let mut values = Evaluations::new(); + for i in 0..num_points_in_query_set { + let point = rand_point(num_vars, rng); + for j in 0..num_equations.unwrap() { + let label = format!("query {} eqn {}", i, j); + let mut lc = LinearCombination::empty(label.clone()); + + let mut value = F::zero(); + let should_have_degree_bounds: bool = rng.gen(); + for (k, label) in labels.iter().enumerate() { + if should_have_degree_bounds { + value += &polynomials[k].evaluate(&point); + lc.push((F::one(), label.to_string().into())); + break; } else { - assert!(poly.degree_bound().is_none()); - let coeff = F::rand(rng); - value += &(coeff * poly.evaluate(&point)); - lc.push((coeff, label.to_string().into())); + let poly = &polynomials[k]; + if poly.degree_bound().is_some() { + continue; + } else { + assert!(poly.degree_bound().is_none()); + let coeff = F::rand(rng); + value += &(coeff * poly.evaluate(&point)); + lc.push((coeff, label.to_string().into())); + } } } + values.insert((label.clone(), point.clone()), value); + if !lc.is_empty() { + linear_combinations.push(lc); + // Insert query + query_set.insert((label.clone(), (format!("{}", i), point.clone()))); + } } - values.insert((label.clone(), point.clone()), value); - if !lc.is_empty() { - linear_combinations.push(lc); - // Insert query - query_set.insert((label.clone(), (format!("{}", i), point.clone()))); + } + if linear_combinations.is_empty() { + continue; + } + println!("Generated query set"); + println!("Linear combinations: {:?}", linear_combinations); + + let proof = PC::open_combinations( + &ck, + &linear_combinations, + &polynomials, + &comms, + &query_set, + &mut (challenge_gen.clone()), + &rands, + Some(rng), + )?; + println!("Generated proof"); + let result = PC::check_combinations( + &vk, + &linear_combinations, + &comms, + &query_set, + &values, + &proof, + &mut (challenge_gen.clone()), + rng, + )?; + if !result { + println!( + "Failed with {} polynomials, num_points_in_query_set: {:?}", + num_polynomials, num_points_in_query_set + ); + println!("Degree of polynomials:",); + for poly in polynomials { + println!("Degree: {:?}", poly.degree()); } } - } - if linear_combinations.is_empty() { - continue; - } - println!("Generated query set"); - println!("Linear combinations: {:?}", linear_combinations); - - let opening_challenge = F::rand(rng); - let proof = PC::open_combinations( - &ck, - &linear_combinations, - &polynomials, - &comms, - &query_set, - opening_challenge, - &rands, - Some(rng), - )?; - println!("Generated proof"); - let result = PC::check_combinations( - &vk, - &linear_combinations, - &comms, - &query_set, - &values, - &proof, - opening_challenge, - rng, - )?; - if !result { - println!( - "Failed with {} polynomials, num_points_in_query_set: {:?}", - num_polynomials, num_points_in_query_set + assert!( + result, + "proof was incorrect, equations: {:#?}", + linear_combinations ); - println!("Degree of polynomials:",); - for poly in polynomials { - println!("Degree: {:?}", poly.degree()); - } } - assert!( - result, - "proof was incorrect, equations: {:#?}", - linear_combinations - ); } Ok(()) } - pub fn single_poly_test( + pub fn single_poly_test( num_vars: Option, rand_poly: fn(usize, Option, &mut StdRng) -> P, rand_point: fn(Option, &mut StdRng) -> P::Point, + sponge: fn() -> S, ) -> Result<(), PC::Error> where - F: Field, + F: PrimeField, P: Polynomial, - PC: PolynomialCommitment, + PC: PolynomialCommitment, + S: CryptographicSponge, { let info = TestInfo { num_iters: 100, @@ -1129,18 +1000,21 @@ pub mod tests { num_equations: None, rand_poly, rand_point, + sponge, }; - test_template::(info) + test_template::(info) } - pub fn linear_poly_degree_bound_test( + pub fn linear_poly_degree_bound_test( rand_poly: fn(usize, Option, &mut StdRng) -> P, rand_point: fn(Option, &mut StdRng) -> P::Point, + sponge: fn() -> S, ) -> Result<(), PC::Error> where - F: Field, + F: PrimeField, P: Polynomial, - PC: PolynomialCommitment, + PC: PolynomialCommitment, + S: CryptographicSponge, { let info = TestInfo { num_iters: 100, @@ -1153,18 +1027,21 @@ pub mod tests { num_equations: None, rand_poly, rand_point, + sponge, }; - test_template::(info) + test_template::(info) } - pub fn single_poly_degree_bound_test( + pub fn single_poly_degree_bound_test( rand_poly: fn(usize, Option, &mut StdRng) -> P, rand_point: fn(Option, &mut StdRng) -> P::Point, + sponge: fn() -> S, ) -> Result<(), PC::Error> where - F: Field, + F: PrimeField, P: Polynomial, - PC: PolynomialCommitment, + PC: PolynomialCommitment, + S: CryptographicSponge, { let info = TestInfo { num_iters: 100, @@ -1177,18 +1054,21 @@ pub mod tests { num_equations: None, rand_poly, rand_point, + sponge, }; - test_template::(info) + test_template::(info) } - pub fn quadratic_poly_degree_bound_multiple_queries_test( + pub fn quadratic_poly_degree_bound_multiple_queries_test( rand_poly: fn(usize, Option, &mut StdRng) -> P, rand_point: fn(Option, &mut StdRng) -> P::Point, + sponge: fn() -> S, ) -> Result<(), PC::Error> where - F: Field, + F: PrimeField, P: Polynomial, - PC: PolynomialCommitment, + PC: PolynomialCommitment, + S: CryptographicSponge, { let info = TestInfo { num_iters: 100, @@ -1201,18 +1081,21 @@ pub mod tests { num_equations: None, rand_poly, rand_point, + sponge, }; - test_template::(info) + test_template::(info) } - pub fn single_poly_degree_bound_multiple_queries_test( + pub fn single_poly_degree_bound_multiple_queries_test( rand_poly: fn(usize, Option, &mut StdRng) -> P, rand_point: fn(Option, &mut StdRng) -> P::Point, + sponge: fn() -> S, ) -> Result<(), PC::Error> where - F: Field, + F: PrimeField, P: Polynomial, - PC: PolynomialCommitment, + PC: PolynomialCommitment, + S: CryptographicSponge, { let info = TestInfo { num_iters: 100, @@ -1225,18 +1108,21 @@ pub mod tests { num_equations: None, rand_poly, rand_point, + sponge, }; - test_template::(info) + test_template::(info) } - pub fn two_polys_degree_bound_single_query_test( + pub fn two_polys_degree_bound_single_query_test( rand_poly: fn(usize, Option, &mut StdRng) -> P, rand_point: fn(Option, &mut StdRng) -> P::Point, + sponge: fn() -> S, ) -> Result<(), PC::Error> where - F: Field, + F: PrimeField, P: Polynomial, - PC: PolynomialCommitment, + PC: PolynomialCommitment, + S: CryptographicSponge, { let info = TestInfo { num_iters: 100, @@ -1249,19 +1135,22 @@ pub mod tests { num_equations: None, rand_poly, rand_point, + sponge, }; - test_template::(info) + test_template::(info) } - pub fn full_end_to_end_test( + pub fn full_end_to_end_test( num_vars: Option, rand_poly: fn(usize, Option, &mut StdRng) -> P, rand_point: fn(Option, &mut StdRng) -> P::Point, + sponge: fn() -> S, ) -> Result<(), PC::Error> where - F: Field, + F: PrimeField, P: Polynomial, - PC: PolynomialCommitment, + PC: PolynomialCommitment, + S: CryptographicSponge, { let info = TestInfo { num_iters: 100, @@ -1274,19 +1163,22 @@ pub mod tests { num_equations: None, rand_poly, rand_point, + sponge, }; - test_template::(info) + test_template::(info) } - pub fn full_end_to_end_equation_test( + pub fn full_end_to_end_equation_test( num_vars: Option, rand_poly: fn(usize, Option, &mut StdRng) -> P, rand_point: fn(Option, &mut StdRng) -> P::Point, + sponge: fn() -> S, ) -> Result<(), PC::Error> where - F: Field, + F: PrimeField, P: Polynomial, - PC: PolynomialCommitment, + PC: PolynomialCommitment, + S: CryptographicSponge, { let info = TestInfo { num_iters: 100, @@ -1299,19 +1191,22 @@ pub mod tests { num_equations: Some(10), rand_poly, rand_point, + sponge, }; - equation_test_template::(info) + equation_test_template::(info) } - pub fn single_equation_test( + pub fn single_equation_test( num_vars: Option, rand_poly: fn(usize, Option, &mut StdRng) -> P, rand_point: fn(Option, &mut StdRng) -> P::Point, + sponge: fn() -> S, ) -> Result<(), PC::Error> where - F: Field, + F: PrimeField, P: Polynomial, - PC: PolynomialCommitment, + PC: PolynomialCommitment, + S: CryptographicSponge, { let info = TestInfo { num_iters: 100, @@ -1324,19 +1219,22 @@ pub mod tests { num_equations: Some(1), rand_poly, rand_point, + sponge, }; - equation_test_template::(info) + equation_test_template::(info) } - pub fn two_equation_test( + pub fn two_equation_test( num_vars: Option, rand_poly: fn(usize, Option, &mut StdRng) -> P, rand_point: fn(Option, &mut StdRng) -> P::Point, + sponge: fn() -> S, ) -> Result<(), PC::Error> where - F: Field, + F: PrimeField, P: Polynomial, - PC: PolynomialCommitment, + PC: PolynomialCommitment, + S: CryptographicSponge, { let info = TestInfo { num_iters: 100, @@ -1349,18 +1247,21 @@ pub mod tests { num_equations: Some(2), rand_poly, rand_point, + sponge, }; - equation_test_template::(info) + equation_test_template::(info) } - pub fn two_equation_degree_bound_test( + pub fn two_equation_degree_bound_test( rand_poly: fn(usize, Option, &mut StdRng) -> P, rand_point: fn(Option, &mut StdRng) -> P::Point, + sponge: fn() -> S, ) -> Result<(), PC::Error> where - F: Field, + F: PrimeField, P: Polynomial, - PC: PolynomialCommitment, + PC: PolynomialCommitment, + S: CryptographicSponge, { let info = TestInfo { num_iters: 100, @@ -1373,7 +1274,41 @@ pub mod tests { num_equations: Some(2), rand_poly, rand_point, + sponge, }; - equation_test_template::(info) + equation_test_template::(info) + } + + pub(crate) fn poseidon_sponge_for_test() -> PoseidonSponge { + PoseidonSponge::new(&poseidon_parameters_for_test()) + } + + /// Generate default parameters for alpha = 17, state-size = 8 + /// + /// WARNING: This poseidon parameter is not secure. Please generate + /// your own parameters according the field you use. + pub(crate) fn poseidon_parameters_for_test() -> PoseidonParameters { + let full_rounds = 8; + let partial_rounds = 31; + let alpha = 17; + + let mds = vec![ + vec![F::one(), F::zero(), F::one()], + vec![F::one(), F::one(), F::zero()], + vec![F::zero(), F::one(), F::one()], + ]; + + let mut ark = Vec::new(); + let mut ark_rng = test_rng(); + + for _ in 0..(full_rounds + partial_rounds) { + let mut res = Vec::new(); + + for _ in 0..3 { + res.push(F::rand(&mut ark_rng)); + } + ark.push(res); + } + PoseidonParameters::new(full_rounds, partial_rounds, alpha, mds, ark) } } diff --git a/src/marlin/marlin_pc/mod.rs b/src/marlin/marlin_pc/mod.rs index d101e3ae..918d5c4c 100644 --- a/src/marlin/marlin_pc/mod.rs +++ b/src/marlin/marlin_pc/mod.rs @@ -1,4 +1,4 @@ -use crate::{kzg10, marlin::Marlin, PCCommitterKey}; +use crate::{kzg10, marlin::Marlin, PCCommitterKey, CHALLENGE_SIZE}; use crate::{BTreeMap, BTreeSet, ToString, Vec}; use crate::{BatchLCProof, Error, Evaluations, QuerySet}; use crate::{LabeledCommitment, LabeledPolynomial, LinearCombination}; @@ -10,6 +10,8 @@ use ark_std::rand::RngCore; use ark_std::{marker::PhantomData, ops::Div, vec}; mod data_structures; +use crate::challenge::ChallengeGenerator; +use ark_sponge::CryptographicSponge; pub use data_structures::*; /// Polynomial commitment based on [[KZG10]][kzg], with degree enforcement, batching, @@ -24,9 +26,10 @@ pub use data_structures::*; /// /// [kzg]: http://cacr.uwaterloo.ca/techreports/2010/cacr2010-10.pdf /// [marlin]: https://eprint.iacr.org/2019/104 -pub struct MarlinKZG10> { +pub struct MarlinKZG10, S: CryptographicSponge> { _engine: PhantomData, _poly: PhantomData

, + _sponge: PhantomData, } pub(crate) fn shift_polynomial>( @@ -50,10 +53,11 @@ pub(crate) fn shift_polynomial>( } } -impl PolynomialCommitment for MarlinKZG10 +impl PolynomialCommitment for MarlinKZG10 where E: PairingEngine, P: UVPolynomial, + S: CryptographicSponge, for<'a, 'b> &'a P: Div<&'b P, Output = P>, { type UniversalParams = UniversalParams; @@ -242,12 +246,12 @@ where } /// On input a polynomial `p` and a point `point`, outputs a proof for the same. - fn open_individual_opening_challenges<'a>( + fn open<'a>( ck: &Self::CommitterKey, labeled_polynomials: impl IntoIterator>, _commitments: impl IntoIterator>, point: &'a P::Point, - opening_challenges: &dyn Fn(u64) -> E::Fr, + opening_challenges: &mut ChallengeGenerator, rands: impl IntoIterator, _rng: Option<&mut dyn RngCore>, ) -> Result @@ -263,7 +267,6 @@ where let mut shifted_r_witness = P::zero(); let mut enforce_degree_bound = false; - let mut opening_challenge_counter = 0; for (polynomial, rand) in labeled_polynomials.into_iter().zip(rands) { let degree_bound = polynomial.degree_bound(); assert_eq!(degree_bound.is_some(), rand.shifted_rand.is_some()); @@ -279,9 +282,8 @@ where &polynomial, )?; - // compute challenge^j and challenge^{j+1}. - let challenge_j = opening_challenges(opening_challenge_counter); - opening_challenge_counter += 1; + // compute next challenges challenge^j and challenge^{j+1}. + let challenge_j = opening_challenges.try_next_challenge_of_size(CHALLENGE_SIZE); assert_eq!(degree_bound.is_some(), rand.shifted_rand.is_some()); @@ -297,8 +299,7 @@ where *point, &shifted_rand, )?; - let challenge_j_1 = opening_challenges(opening_challenge_counter); - opening_challenge_counter += 1; + let challenge_j_1 = opening_challenges.try_next_challenge_of_size(CHALLENGE_SIZE); let shifted_witness = shift_polynomial(ck, &witness, degree_bound); @@ -340,13 +341,13 @@ where /// Verifies that `value` is the evaluation at `x` of the polynomial /// committed inside `comm`. - fn check_individual_opening_challenges<'a>( + fn check<'a>( vk: &Self::VerifierKey, commitments: impl IntoIterator>, point: &'a P::Point, values: impl IntoIterator, proof: &Self::Proof, - opening_challenges: &dyn Fn(u64) -> E::Fr, + opening_challenges: &mut ChallengeGenerator, _rng: Option<&mut dyn RngCore>, ) -> Result where @@ -354,7 +355,7 @@ where { let check_time = start_timer!(|| "Checking evaluations"); let (combined_comm, combined_value) = - Marlin::accumulate_commitments_and_values_individual_opening_challenges( + Marlin::::accumulate_commitments_and_values( commitments, values, opening_challenges, @@ -366,25 +367,26 @@ where Ok(result) } - fn batch_check_individual_opening_challenges<'a, R: RngCore>( + fn batch_check<'a, R: RngCore>( vk: &Self::VerifierKey, commitments: impl IntoIterator>, query_set: &QuerySet, values: &Evaluations, proof: &Self::BatchProof, - opening_challenges: &dyn Fn(u64) -> E::Fr, + opening_challenges: &mut ChallengeGenerator, rng: &mut R, ) -> Result where Self::Commitment: 'a, { - let (combined_comms, combined_queries, combined_evals) = Marlin::combine_and_normalize( - commitments, - query_set, - values, - opening_challenges, - Some(vk), - )?; + let (combined_comms, combined_queries, combined_evals) = + Marlin::::combine_and_normalize( + commitments, + query_set, + values, + opening_challenges, + Some(vk), + )?; assert_eq!(proof.len(), combined_queries.len()); let proof_time = start_timer!(|| "Checking KZG10::Proof"); let result = kzg10::KZG10::batch_check( @@ -399,22 +401,22 @@ where Ok(result) } - fn open_combinations_individual_opening_challenges<'a>( + fn open_combinations<'a>( ck: &Self::CommitterKey, lc_s: impl IntoIterator>, polynomials: impl IntoIterator>, commitments: impl IntoIterator>, query_set: &QuerySet, - opening_challenges: &dyn Fn(u64) -> E::Fr, + opening_challenges: &mut ChallengeGenerator, rands: impl IntoIterator, rng: Option<&mut dyn RngCore>, - ) -> Result, Self::Error> + ) -> Result, Self::Error> where P: 'a, Self::Randomness: 'a, Self::Commitment: 'a, { - Marlin::open_combinations_individual_opening_challenges( + Marlin::::open_combinations( ck, lc_s, polynomials, @@ -428,20 +430,20 @@ where /// Checks that `values` are the true evaluations at `query_set` of the polynomials /// committed in `labeled_commitments`. - fn check_combinations_individual_opening_challenges<'a, R: RngCore>( + fn check_combinations<'a, R: RngCore>( vk: &Self::VerifierKey, lc_s: impl IntoIterator>, commitments: impl IntoIterator>, query_set: &QuerySet, evaluations: &Evaluations, - proof: &BatchLCProof, - opening_challenges: &dyn Fn(u64) -> E::Fr, + proof: &BatchLCProof, + opening_challenges: &mut ChallengeGenerator, rng: &mut R, ) -> Result where Self::Commitment: 'a, { - Marlin::check_combinations_individual_opening_challenges( + Marlin::::check_combinations( vk, lc_s, commitments, @@ -455,12 +457,12 @@ where /// On input a list of labeled polynomials and a query set, `open` outputs a proof of evaluation /// of the polynomials at the points in the query set. - fn batch_open_individual_opening_challenges<'a>( + fn batch_open<'a>( ck: &CommitterKey, labeled_polynomials: impl IntoIterator>, commitments: impl IntoIterator>>, query_set: &QuerySet, - opening_challenges: &dyn Fn(u64) -> E::Fr, + opening_challenges: &mut ChallengeGenerator, rands: impl IntoIterator, rng: Option<&mut dyn RngCore>, ) -> Result>, Error> @@ -510,7 +512,7 @@ where } let proof_time = start_timer!(|| "Creating proof"); - let proof = Self::open_individual_opening_challenges( + let proof = Self::open( ck, query_polys, query_comms, @@ -539,14 +541,19 @@ mod tests { use ark_ec::PairingEngine; use ark_ff::UniformRand; use ark_poly::{univariate::DensePolynomial as DensePoly, UVPolynomial}; + use ark_sponge::poseidon::PoseidonSponge; use ark_std::rand::rngs::StdRng; type UniPoly_381 = DensePoly<::Fr>; type UniPoly_377 = DensePoly<::Fr>; - type PC = MarlinKZG10; - type PC_Bls12_381 = PC; - type PC_Bls12_377 = PC; + type PC = MarlinKZG10; + + type Sponge_Bls12_381 = PoseidonSponge<::Fr>; + type Sponge_Bls12_377 = PoseidonSponge<::Fr>; + + type PC_Bls12_381 = PC; + type PC_Bls12_377 = PC; fn rand_poly( degree: usize, @@ -571,16 +578,18 @@ mod tests { #[test] fn single_poly_test() { use crate::tests::*; - single_poly_test::<_, _, PC_Bls12_377>( + single_poly_test::<_, _, PC_Bls12_377, _>( None, rand_poly::, rand_point::, + poseidon_sponge_for_test, ) .expect("test failed for bls12-377"); - single_poly_test::<_, _, PC_Bls12_381>( + single_poly_test::<_, _, PC_Bls12_381, _>( None, rand_poly::, rand_point::, + poseidon_sponge_for_test, ) .expect("test failed for bls12-381"); } @@ -588,16 +597,18 @@ mod tests { #[test] fn constant_poly_test() { use crate::tests::*; - single_poly_test::<_, _, PC_Bls12_377>( + single_poly_test::<_, _, PC_Bls12_377, _>( None, constant_poly::, rand_point::, + poseidon_sponge_for_test, ) .expect("test failed for bls12-377"); - single_poly_test::<_, _, PC_Bls12_381>( + single_poly_test::<_, _, PC_Bls12_381, _>( None, constant_poly::, rand_point::, + poseidon_sponge_for_test, ) .expect("test failed for bls12-381"); } @@ -605,14 +616,16 @@ mod tests { #[test] fn quadratic_poly_degree_bound_multiple_queries_test() { use crate::tests::*; - quadratic_poly_degree_bound_multiple_queries_test::<_, _, PC_Bls12_377>( + quadratic_poly_degree_bound_multiple_queries_test::<_, _, PC_Bls12_377, _>( rand_poly::, rand_point::, + poseidon_sponge_for_test, ) .expect("test failed for bls12-377"); - quadratic_poly_degree_bound_multiple_queries_test::<_, _, PC_Bls12_381>( + quadratic_poly_degree_bound_multiple_queries_test::<_, _, PC_Bls12_381, _>( rand_poly::, rand_point::, + poseidon_sponge_for_test, ) .expect("test failed for bls12-381"); } @@ -620,14 +633,16 @@ mod tests { #[test] fn linear_poly_degree_bound_test() { use crate::tests::*; - linear_poly_degree_bound_test::<_, _, PC_Bls12_377>( + linear_poly_degree_bound_test::<_, _, PC_Bls12_377, _>( rand_poly::, rand_point::, + poseidon_sponge_for_test, ) .expect("test failed for bls12-377"); - linear_poly_degree_bound_test::<_, _, PC_Bls12_381>( + linear_poly_degree_bound_test::<_, _, PC_Bls12_381, _>( rand_poly::, rand_point::, + poseidon_sponge_for_test, ) .expect("test failed for bls12-381"); } @@ -635,14 +650,16 @@ mod tests { #[test] fn single_poly_degree_bound_test() { use crate::tests::*; - single_poly_degree_bound_test::<_, _, PC_Bls12_377>( + single_poly_degree_bound_test::<_, _, PC_Bls12_377, _>( rand_poly::, rand_point::, + poseidon_sponge_for_test, ) .expect("test failed for bls12-377"); - single_poly_degree_bound_test::<_, _, PC_Bls12_381>( + single_poly_degree_bound_test::<_, _, PC_Bls12_381, _>( rand_poly::, rand_point::, + poseidon_sponge_for_test, ) .expect("test failed for bls12-381"); } @@ -650,14 +667,16 @@ mod tests { #[test] fn single_poly_degree_bound_multiple_queries_test() { use crate::tests::*; - single_poly_degree_bound_multiple_queries_test::<_, _, PC_Bls12_377>( + single_poly_degree_bound_multiple_queries_test::<_, _, PC_Bls12_377, _>( rand_poly::, rand_point::, + poseidon_sponge_for_test, ) .expect("test failed for bls12-377"); - single_poly_degree_bound_multiple_queries_test::<_, _, PC_Bls12_381>( + single_poly_degree_bound_multiple_queries_test::<_, _, PC_Bls12_381, _>( rand_poly::, rand_point::, + poseidon_sponge_for_test, ) .expect("test failed for bls12-381"); } @@ -665,14 +684,16 @@ mod tests { #[test] fn two_polys_degree_bound_single_query_test() { use crate::tests::*; - two_polys_degree_bound_single_query_test::<_, _, PC_Bls12_377>( + two_polys_degree_bound_single_query_test::<_, _, PC_Bls12_377, _>( rand_poly::, rand_point::, + poseidon_sponge_for_test, ) .expect("test failed for bls12-377"); - two_polys_degree_bound_single_query_test::<_, _, PC_Bls12_381>( + two_polys_degree_bound_single_query_test::<_, _, PC_Bls12_381, _>( rand_poly::, rand_point::, + poseidon_sponge_for_test, ) .expect("test failed for bls12-381"); } @@ -680,17 +701,19 @@ mod tests { #[test] fn full_end_to_end_test() { use crate::tests::*; - full_end_to_end_test::<_, _, PC_Bls12_377>( + full_end_to_end_test::<_, _, PC_Bls12_377, _>( None, rand_poly::, rand_point::, + poseidon_sponge_for_test, ) .expect("test failed for bls12-377"); println!("Finished bls12-377"); - full_end_to_end_test::<_, _, PC_Bls12_381>( + full_end_to_end_test::<_, _, PC_Bls12_381, _>( None, rand_poly::, rand_point::, + poseidon_sponge_for_test, ) .expect("test failed for bls12-381"); println!("Finished bls12-381"); @@ -699,17 +722,19 @@ mod tests { #[test] fn single_equation_test() { use crate::tests::*; - single_equation_test::<_, _, PC_Bls12_377>( + single_equation_test::<_, _, PC_Bls12_377, _>( None, rand_poly::, rand_point::, + poseidon_sponge_for_test, ) .expect("test failed for bls12-377"); println!("Finished bls12-377"); - single_equation_test::<_, _, PC_Bls12_381>( + single_equation_test::<_, _, PC_Bls12_381, _>( None, rand_poly::, rand_point::, + poseidon_sponge_for_test, ) .expect("test failed for bls12-381"); println!("Finished bls12-381"); @@ -718,17 +743,19 @@ mod tests { #[test] fn two_equation_test() { use crate::tests::*; - two_equation_test::<_, _, PC_Bls12_377>( + two_equation_test::<_, _, PC_Bls12_377, _>( None, rand_poly::, rand_point::, + poseidon_sponge_for_test, ) .expect("test failed for bls12-377"); println!("Finished bls12-377"); - two_equation_test::<_, _, PC_Bls12_381>( + two_equation_test::<_, _, PC_Bls12_381, _>( None, rand_poly::, rand_point::, + poseidon_sponge_for_test, ) .expect("test failed for bls12-381"); println!("Finished bls12-381"); @@ -737,15 +764,17 @@ mod tests { #[test] fn two_equation_degree_bound_test() { use crate::tests::*; - two_equation_degree_bound_test::<_, _, PC_Bls12_377>( + two_equation_degree_bound_test::<_, _, PC_Bls12_377, _>( rand_poly::, rand_point::, + poseidon_sponge_for_test, ) .expect("test failed for bls12-377"); println!("Finished bls12-377"); - two_equation_degree_bound_test::<_, _, PC_Bls12_381>( + two_equation_degree_bound_test::<_, _, PC_Bls12_381, _>( rand_poly::, rand_point::, + poseidon_sponge_for_test, ) .expect("test failed for bls12-381"); println!("Finished bls12-381"); @@ -754,17 +783,19 @@ mod tests { #[test] fn full_end_to_end_equation_test() { use crate::tests::*; - full_end_to_end_equation_test::<_, _, PC_Bls12_377>( + full_end_to_end_equation_test::<_, _, PC_Bls12_377, _>( None, rand_poly::, rand_point::, + poseidon_sponge_for_test, ) .expect("test failed for bls12-377"); println!("Finished bls12-377"); - full_end_to_end_equation_test::<_, _, PC_Bls12_381>( + full_end_to_end_equation_test::<_, _, PC_Bls12_381, _>( None, rand_poly::, rand_point::, + poseidon_sponge_for_test, ) .expect("test failed for bls12-381"); println!("Finished bls12-381"); @@ -774,15 +805,17 @@ mod tests { #[should_panic] fn bad_degree_bound_test() { use crate::tests::*; - bad_degree_bound_test::<_, _, PC_Bls12_377>( + bad_degree_bound_test::<_, _, PC_Bls12_377, _>( rand_poly::, rand_point::, + poseidon_sponge_for_test, ) .expect("test failed for bls12-377"); println!("Finished bls12-377"); - bad_degree_bound_test::<_, _, PC_Bls12_381>( + bad_degree_bound_test::<_, _, PC_Bls12_381, _>( rand_poly::, rand_point::, + poseidon_sponge_for_test, ) .expect("test failed for bls12-381"); println!("Finished bls12-381"); diff --git a/src/marlin/marlin_pst13_pc/mod.rs b/src/marlin/marlin_pst13_pc/mod.rs index 9a268b23..d418eb86 100644 --- a/src/marlin/marlin_pst13_pc/mod.rs +++ b/src/marlin/marlin_pst13_pc/mod.rs @@ -1,6 +1,7 @@ use crate::{ kzg10, marlin::{marlin_pc, Marlin}, + CHALLENGE_SIZE, }; use crate::{BatchLCProof, Error, Evaluations, QuerySet}; use crate::{LabeledCommitment, LabeledPolynomial, LinearCombination}; @@ -21,6 +22,8 @@ pub use data_structures::*; mod combinations; use combinations::*; +use crate::challenge::ChallengeGenerator; +use ark_sponge::CryptographicSponge; #[cfg(feature = "parallel")] use rayon::prelude::*; @@ -30,12 +33,13 @@ use rayon::prelude::*; /// /// [pst]: https://eprint.iacr.org/2011/587 /// [marlin]: https://eprint.iacr.org/2019/104 -pub struct MarlinPST13> { +pub struct MarlinPST13, S: CryptographicSponge> { _engine: PhantomData, _poly: PhantomData

, + _sponge: PhantomData, } -impl> MarlinPST13 { +impl, S: CryptographicSponge> MarlinPST13 { /// Given some point `z`, compute the quotients `w_i(X)` s.t /// /// `p(X) - p(z) = (X_1-z_1)*w_1(X) + (X_2-z_2)*w_2(X) + ... + (X_l-z_l)*w_l(X)` @@ -136,10 +140,11 @@ impl> MarlinPST13 { } } -impl PolynomialCommitment for MarlinPST13 +impl PolynomialCommitment for MarlinPST13 where E: PairingEngine, P: MVPolynomial + Sync, + S: CryptographicSponge, P::Point: Index, { type UniversalParams = UniversalParams; @@ -438,12 +443,12 @@ where } /// On input a polynomial `p` and a point `point`, outputs a proof for the same. - fn open_individual_opening_challenges<'a>( + fn open<'a>( ck: &Self::CommitterKey, labeled_polynomials: impl IntoIterator>, _commitments: impl IntoIterator>, point: &P::Point, - opening_challenges: &dyn Fn(u64) -> E::Fr, + opening_challenges: &mut ChallengeGenerator, rands: impl IntoIterator, _rng: Option<&mut dyn RngCore>, ) -> Result @@ -455,13 +460,11 @@ where // Compute random linear combinations of committed polynomials and randomness let mut p = P::zero(); let mut r = Randomness::empty(); - let mut opening_challenge_counter = 0; for (polynomial, rand) in labeled_polynomials.into_iter().zip(rands) { Self::check_degrees_and_bounds(ck.supported_degree, &polynomial)?; // compute challenge^j and challenge^{j+1}. - let challenge_j = opening_challenges(opening_challenge_counter); - opening_challenge_counter += 1; + let challenge_j = opening_challenges.try_next_challenge_of_size(CHALLENGE_SIZE); p += (challenge_j, polynomial.polynomial()); r += (challenge_j, rand); @@ -537,13 +540,13 @@ where /// Verifies that `value` is the evaluation at `x` of the polynomial /// committed inside `comm`. - fn check_individual_opening_challenges<'a>( + fn check<'a>( vk: &Self::VerifierKey, commitments: impl IntoIterator>, point: &'a P::Point, values: impl IntoIterator, proof: &Self::Proof, - opening_challenges: &dyn Fn(u64) -> E::Fr, + opening_challenges: &mut ChallengeGenerator, _rng: Option<&mut dyn RngCore>, ) -> Result where @@ -552,7 +555,7 @@ where let check_time = start_timer!(|| "Checking evaluations"); // Accumulate commitments and values let (combined_comm, combined_value) = - Marlin::accumulate_commitments_and_values_individual_opening_challenges( + Marlin::::accumulate_commitments_and_values( commitments, values, opening_challenges, @@ -580,25 +583,26 @@ where Ok(lhs == rhs) } - fn batch_check_individual_opening_challenges<'a, R: RngCore>( + fn batch_check<'a, R: RngCore>( vk: &Self::VerifierKey, commitments: impl IntoIterator>, query_set: &QuerySet, values: &Evaluations, proof: &Self::BatchProof, - opening_challenges: &dyn Fn(u64) -> E::Fr, + opening_challenges: &mut ChallengeGenerator, rng: &mut R, ) -> Result where Self::Commitment: 'a, { - let (combined_comms, combined_queries, combined_evals) = Marlin::combine_and_normalize( - commitments, - query_set, - values, - opening_challenges, - None, - )?; + let (combined_comms, combined_queries, combined_evals) = + Marlin::::combine_and_normalize( + commitments, + query_set, + values, + opening_challenges, + None, + )?; let check_time = start_timer!(|| format!("Checking {} evaluation proofs", combined_comms.len())); let g = vk.g.into_projective(); @@ -655,24 +659,24 @@ where Ok(result) } - fn open_combinations_individual_opening_challenges<'a>( + fn open_combinations<'a>( ck: &Self::CommitterKey, - lc_s: impl IntoIterator>, + linear_combinations: impl IntoIterator>, polynomials: impl IntoIterator>, commitments: impl IntoIterator>, query_set: &QuerySet, - opening_challenges: &dyn Fn(u64) -> E::Fr, + opening_challenges: &mut ChallengeGenerator, rands: impl IntoIterator, rng: Option<&mut dyn RngCore>, - ) -> Result, Self::Error> + ) -> Result, Self::Error> where P: 'a, Self::Randomness: 'a, Self::Commitment: 'a, { - Marlin::open_combinations_individual_opening_challenges( + Marlin::::open_combinations( ck, - lc_s, + linear_combinations, polynomials, commitments, query_set, @@ -684,25 +688,25 @@ where /// Checks that `values` are the true evaluations at `query_set` of the polynomials /// committed in `labeled_commitments`. - fn check_combinations_individual_opening_challenges<'a, R: RngCore>( + fn check_combinations<'a, R: RngCore>( vk: &Self::VerifierKey, - lc_s: impl IntoIterator>, + linear_combinations: impl IntoIterator>, commitments: impl IntoIterator>, - query_set: &QuerySet, - evaluations: &Evaluations, - proof: &BatchLCProof, - opening_challenges: &dyn Fn(u64) -> E::Fr, + eqn_query_set: &QuerySet, + eqn_evaluations: &Evaluations, + proof: &BatchLCProof, + opening_challenges: &mut ChallengeGenerator, rng: &mut R, ) -> Result where Self::Commitment: 'a, { - Marlin::check_combinations_individual_opening_challenges( + Marlin::::check_combinations( vk, - lc_s, + linear_combinations, commitments, - query_set, - evaluations, + eqn_query_set, + eqn_evaluations, proof, opening_challenges, rng, @@ -722,14 +726,19 @@ mod tests { multivariate::{SparsePolynomial as SparsePoly, SparseTerm}, MVPolynomial, }; + use ark_sponge::poseidon::PoseidonSponge; use ark_std::rand::rngs::StdRng; type MVPoly_381 = SparsePoly<::Fr, SparseTerm>; type MVPoly_377 = SparsePoly<::Fr, SparseTerm>; - type PC = MarlinPST13; - type PC_Bls12_381 = PC; - type PC_Bls12_377 = PC; + type PC = MarlinPST13; + + type Sponge_bls12_381 = PoseidonSponge<::Fr>; + type Sponge_Bls12_377 = PoseidonSponge<::Fr>; + + type PC_Bls12_381 = PC; + type PC_Bls12_377 = PC; fn rand_poly( degree: usize, @@ -752,16 +761,18 @@ mod tests { fn single_poly_test() { use crate::tests::*; let num_vars = Some(10); - single_poly_test::<_, _, PC_Bls12_377>( + single_poly_test::<_, _, PC_Bls12_377, _>( num_vars, rand_poly::, rand_point::, + poseidon_sponge_for_test, ) .expect("test failed for bls12-377"); - single_poly_test::<_, _, PC_Bls12_381>( + single_poly_test::<_, _, PC_Bls12_381, _>( num_vars, rand_poly::, rand_point::, + poseidon_sponge_for_test, ) .expect("test failed for bls12-381"); } @@ -770,17 +781,19 @@ mod tests { fn full_end_to_end_test() { use crate::tests::*; let num_vars = Some(10); - full_end_to_end_test::<_, _, PC_Bls12_377>( + full_end_to_end_test::<_, _, PC_Bls12_377, _>( num_vars, rand_poly::, rand_point::, + poseidon_sponge_for_test, ) .expect("test failed for bls12-377"); println!("Finished bls12-377"); - full_end_to_end_test::<_, _, PC_Bls12_381>( + full_end_to_end_test::<_, _, PC_Bls12_381, _>( num_vars, rand_poly::, rand_point::, + poseidon_sponge_for_test, ) .expect("test failed for bls12-381"); println!("Finished bls12-381"); @@ -790,17 +803,19 @@ mod tests { fn single_equation_test() { use crate::tests::*; let num_vars = Some(10); - single_equation_test::<_, _, PC_Bls12_377>( + single_equation_test::<_, _, PC_Bls12_377, _>( num_vars, rand_poly::, rand_point::, + poseidon_sponge_for_test, ) .expect("test failed for bls12-377"); println!("Finished bls12-377"); - single_equation_test::<_, _, PC_Bls12_381>( + single_equation_test::<_, _, PC_Bls12_381, _>( num_vars, rand_poly::, rand_point::, + poseidon_sponge_for_test, ) .expect("test failed for bls12-381"); println!("Finished bls12-381"); @@ -810,17 +825,19 @@ mod tests { fn two_equation_test() { use crate::tests::*; let num_vars = Some(10); - two_equation_test::<_, _, PC_Bls12_377>( + two_equation_test::<_, _, PC_Bls12_377, _>( num_vars, rand_poly::, rand_point::, + poseidon_sponge_for_test, ) .expect("test failed for bls12-377"); println!("Finished bls12-377"); - two_equation_test::<_, _, PC_Bls12_381>( + two_equation_test::<_, _, PC_Bls12_381, _>( num_vars, rand_poly::, rand_point::, + poseidon_sponge_for_test, ) .expect("test failed for bls12-381"); println!("Finished bls12-381"); @@ -830,17 +847,19 @@ mod tests { fn full_end_to_end_equation_test() { use crate::tests::*; let num_vars = Some(10); - full_end_to_end_equation_test::<_, _, PC_Bls12_377>( + full_end_to_end_equation_test::<_, _, PC_Bls12_377, _>( num_vars, rand_poly::, rand_point::, + poseidon_sponge_for_test, ) .expect("test failed for bls12-377"); println!("Finished bls12-377"); - full_end_to_end_equation_test::<_, _, PC_Bls12_381>( + full_end_to_end_equation_test::<_, _, PC_Bls12_381, _>( num_vars, rand_poly::, rand_point::, + poseidon_sponge_for_test, ) .expect("test failed for bls12-381"); println!("Finished bls12-381"); diff --git a/src/marlin/mod.rs b/src/marlin/mod.rs index 12c91976..05ba0570 100644 --- a/src/marlin/mod.rs +++ b/src/marlin/mod.rs @@ -1,3 +1,4 @@ +use crate::{challenge::ChallengeGenerator, CHALLENGE_SIZE}; use crate::{kzg10, Error}; use crate::{BTreeMap, BTreeSet, Debug, RngCore, String, ToString, Vec}; use crate::{BatchLCProof, LabeledPolynomial, LinearCombination}; @@ -5,6 +6,7 @@ use crate::{Evaluations, LabeledCommitment, QuerySet}; use crate::{PCRandomness, Polynomial, PolynomialCommitment}; use ark_ec::{AffineCurve, PairingEngine, ProjectiveCurve}; use ark_ff::{One, Zero}; +use ark_sponge::CryptographicSponge; use ark_std::{convert::TryInto, hash::Hash, ops::AddAssign}; /// Polynomial commitment scheme from [[KZG10]][kzg] that enforces @@ -24,11 +26,26 @@ pub mod marlin_pc; pub mod marlin_pst13_pc; /// Common functionalities between `marlin_pc` and `marlin_pst13_pc` -struct Marlin { +struct Marlin +where + E: PairingEngine, + S: CryptographicSponge, + P: Polynomial, + PC: PolynomialCommitment, +{ _engine: core::marker::PhantomData, + _sponge: core::marker::PhantomData, + _poly: core::marker::PhantomData

, + _pc: core::marker::PhantomData, } -impl Marlin { +impl Marlin +where + E: PairingEngine, + S: CryptographicSponge, + P: Polynomial, + PC: PolynomialCommitment, +{ /// MSM for `commitments` and `coeffs` fn combine_commitments<'a>( coeffs_and_comms: impl IntoIterator)>, @@ -87,31 +104,28 @@ impl Marlin { .collect() } - /// Accumulate `commitments` and `values` according to `opening_challenge`. - fn accumulate_commitments_and_values_individual_opening_challenges<'a>( + /// Accumulate `commitments` and `values` according to the challenges produces by `challenge_gen`. + fn accumulate_commitments_and_values<'a>( commitments: impl IntoIterator>>, values: impl IntoIterator, - opening_challenges: &dyn Fn(u64) -> E::Fr, + challenge_gen: &mut ChallengeGenerator, vk: Option<&marlin_pc::VerifierKey>, ) -> Result<(E::G1Projective, E::Fr), Error> { let acc_time = start_timer!(|| "Accumulating commitments and values"); let mut combined_comm = E::G1Projective::zero(); let mut combined_value = E::Fr::zero(); - let mut opening_challenge_counter = 0; for (labeled_commitment, value) in commitments.into_iter().zip(values) { let degree_bound = labeled_commitment.degree_bound(); let commitment = labeled_commitment.commitment(); assert_eq!(degree_bound.is_some(), commitment.shifted_comm.is_some()); - let challenge_i = opening_challenges(opening_challenge_counter); - opening_challenge_counter += 1; + let challenge_i = challenge_gen.try_next_challenge_of_size(CHALLENGE_SIZE); combined_comm += &commitment.comm.0.mul(challenge_i); combined_value += &(value * &challenge_i); if let Some(degree_bound) = degree_bound { - let challenge_i_1 = opening_challenges(opening_challenge_counter); - opening_challenge_counter += 1; + let challenge_i_1 = challenge_gen.try_next_challenge_of_size(CHALLENGE_SIZE); let shifted_comm = commitment .shifted_comm @@ -141,7 +155,7 @@ impl Marlin { commitments: impl IntoIterator>>, query_set: &QuerySet, evaluations: &Evaluations, - opening_challenges: &dyn Fn(u64) -> E::Fr, + opening_challenges: &mut ChallengeGenerator, vk: Option<&marlin_pc::VerifierKey>, ) -> Result<(Vec>, Vec, Vec), Error> where @@ -185,7 +199,7 @@ impl Marlin { values_to_combine.push(*v_i); } - let (c, v) = Marlin::accumulate_commitments_and_values_individual_opening_challenges( + let (c, v) = Self::accumulate_commitments_and_values( comms_to_combine, values_to_combine, opening_challenges, @@ -210,22 +224,23 @@ impl Marlin { /// On input a list of polynomials, linear combinations of those polynomials, /// and a query set, `open_combination` outputs a proof of evaluation of /// the combinations at the points in the query set. - fn open_combinations_individual_opening_challenges<'a, P, D, PC>( + fn open_combinations<'a, D>( ck: &PC::CommitterKey, lc_s: impl IntoIterator>, polynomials: impl IntoIterator>, commitments: impl IntoIterator>, query_set: &QuerySet, - opening_challenges: &dyn Fn(u64) -> E::Fr, + opening_challenges: &mut ChallengeGenerator, rands: impl IntoIterator, rng: Option<&mut dyn RngCore>, - ) -> Result, Error> + ) -> Result, Error> where P: 'a + Polynomial, D: Debug + Clone + Hash + Ord + Sync, PC: PolynomialCommitment< E::Fr, P, + S, Commitment = marlin_pc::Commitment, PreparedCommitment = marlin_pc::PreparedCommitment, Error = Error, @@ -281,18 +296,18 @@ impl Marlin { LabeledPolynomial::new(lc_label.clone(), poly, degree_bound, hiding_bound); lc_polynomials.push(lc_poly); lc_randomness.push(randomness); - lc_commitments.push(Marlin::combine_commitments(coeffs_and_comms)); + lc_commitments.push(Self::combine_commitments(coeffs_and_comms)); lc_info.push((lc_label, degree_bound)); } - let comms = Marlin::normalize_commitments(lc_commitments); + let comms = Self::normalize_commitments(lc_commitments); let lc_commitments = lc_info .into_iter() .zip(comms) .map(|((label, d), c)| LabeledCommitment::new(label, c, d)) .collect::>(); - let proof = PC::batch_open_individual_opening_challenges( + let proof = PC::batch_open( ck, lc_polynomials.iter(), lc_commitments.iter(), @@ -305,14 +320,14 @@ impl Marlin { Ok(BatchLCProof { proof, evals: None }) } - fn check_combinations_individual_opening_challenges<'a, R, P, D, PC>( + fn check_combinations<'a, R, D>( vk: &PC::VerifierKey, lc_s: impl IntoIterator>, commitments: impl IntoIterator>, query_set: &QuerySet, evaluations: &Evaluations, - proof: &BatchLCProof, - opening_challenges: &dyn Fn(u64) -> E::Fr, + proof: &BatchLCProof, + opening_challenges: &mut ChallengeGenerator, rng: &mut R, ) -> Result where @@ -322,6 +337,7 @@ impl Marlin { PC: PolynomialCommitment< E::Fr, P, + S, Commitment = marlin_pc::Commitment, PreparedCommitment = marlin_pc::PreparedCommitment, Error = Error, @@ -373,13 +389,13 @@ impl Marlin { } let lc_time = start_timer!(|| format!("Combining {} commitments for {}", num_polys, lc_label)); - lc_commitments.push(Marlin::combine_commitments(coeffs_and_comms)); + lc_commitments.push(Self::combine_commitments(coeffs_and_comms)); end_timer!(lc_time); lc_info.push((lc_label, degree_bound)); } end_timer!(lc_processing_time); let combined_comms_norm_time = start_timer!(|| "Normalizing commitments"); - let comms = Marlin::normalize_commitments(lc_commitments); + let comms = Self::normalize_commitments(lc_commitments); let lc_commitments = lc_info .into_iter() .zip(comms) @@ -387,7 +403,7 @@ impl Marlin { .collect::>(); end_timer!(combined_comms_norm_time); - PC::batch_check_individual_opening_challenges( + PC::batch_check( vk, &lc_commitments, &query_set, diff --git a/src/sonic_pc/mod.rs b/src/sonic_pc/mod.rs index 0782dfc1..e02d635f 100644 --- a/src/sonic_pc/mod.rs +++ b/src/sonic_pc/mod.rs @@ -1,4 +1,4 @@ -use crate::{kzg10, PCCommitterKey}; +use crate::{kzg10, PCCommitterKey, CHALLENGE_SIZE}; use crate::{BTreeMap, BTreeSet, String, ToString, Vec}; use crate::{BatchLCProof, Error, Evaluations, QuerySet, UVPolynomial}; use crate::{LabeledCommitment, LabeledPolynomial, LinearCombination}; @@ -10,6 +10,8 @@ use ark_std::rand::RngCore; use ark_std::{convert::TryInto, marker::PhantomData, ops::Div, vec}; mod data_structures; +use crate::challenge::ChallengeGenerator; +use ark_sponge::CryptographicSponge; pub use data_structures::*; /// Polynomial commitment based on [[KZG10]][kzg], with degree enforcement and @@ -22,13 +24,19 @@ pub use data_structures::*; /// [sonic]: https://eprint.iacr.org/2019/099 /// [al]: https://eprint.iacr.org/2019/601 /// [marlin]: https://eprint.iacr.org/2019/1047 -pub struct SonicKZG10> { +pub struct SonicKZG10, S: CryptographicSponge> { _engine: PhantomData, _poly: PhantomData

, + _sponge: PhantomData, } -impl> SonicKZG10 { - fn accumulate_elems_individual_opening_challenges<'a>( +impl SonicKZG10 +where + E: PairingEngine, + P: UVPolynomial, + S: CryptographicSponge, +{ + fn accumulate_elems<'a>( combined_comms: &mut BTreeMap, E::G1Projective>, combined_witness: &mut E::G1Projective, combined_adjusted_witness: &mut E::G1Projective, @@ -37,14 +45,12 @@ impl> SonicKZG10 { point: P::Point, values: impl IntoIterator, proof: &kzg10::Proof, - opening_challenges: &dyn Fn(u64) -> E::Fr, + opening_challenges: &mut ChallengeGenerator, randomizer: Option, ) { let acc_time = start_timer!(|| "Accumulating elements"); - let mut opening_challenge_counter = 0; - let mut curr_challenge = opening_challenges(opening_challenge_counter); - opening_challenge_counter += 1; + let mut curr_challenge = opening_challenges.try_next_challenge_of_size(CHALLENGE_SIZE); // Keeps track of running combination of values let mut combined_values = E::Fr::zero(); @@ -67,8 +73,7 @@ impl> SonicKZG10 { *combined_comms .entry(degree_bound) .or_insert(E::G1Projective::zero()) += &comm_with_challenge; - curr_challenge = opening_challenges(opening_challenge_counter); - opening_challenge_counter += 1; + curr_challenge = opening_challenges.try_next_challenge_of_size(CHALLENGE_SIZE); } // Push expected results into list of elems. Power will be the negative of the expected power @@ -129,10 +134,11 @@ impl> SonicKZG10 { } } -impl PolynomialCommitment for SonicKZG10 +impl PolynomialCommitment for SonicKZG10 where E: PairingEngine, P: UVPolynomial, + S: CryptographicSponge, for<'a, 'b> &'a P: Div<&'b P, Output = P>, { type UniversalParams = UniversalParams; @@ -335,12 +341,12 @@ where Ok((labeled_comms, randomness)) } - fn open_individual_opening_challenges<'a>( + fn open<'a>( ck: &Self::CommitterKey, labeled_polynomials: impl IntoIterator>, _commitments: impl IntoIterator>, point: &'a P::Point, - opening_challenges: &dyn Fn(u64) -> E::Fr, + opening_challenges: &mut ChallengeGenerator, rands: impl IntoIterator, _rng: Option<&mut dyn RngCore>, ) -> Result @@ -352,10 +358,7 @@ where let mut combined_polynomial = P::zero(); let mut combined_rand = kzg10::Randomness::empty(); - let mut opening_challenge_counter = 0; - - let mut curr_challenge = opening_challenges(opening_challenge_counter); - opening_challenge_counter += 1; + let mut curr_challenge = opening_challenges.try_next_challenge_of_size(CHALLENGE_SIZE); for (polynomial, rand) in labeled_polynomials.into_iter().zip(rands) { let enforced_degree_bounds: Option<&[usize]> = ck @@ -372,8 +375,7 @@ where combined_polynomial += (curr_challenge, polynomial.polynomial()); combined_rand += (curr_challenge, rand); - curr_challenge = opening_challenges(opening_challenge_counter); - opening_challenge_counter += 1; + curr_challenge = opening_challenges.try_next_challenge_of_size(CHALLENGE_SIZE); } let proof_time = start_timer!(|| "Creating proof for polynomials"); @@ -383,13 +385,13 @@ where Ok(proof) } - fn check_individual_opening_challenges<'a>( + fn check<'a>( vk: &Self::VerifierKey, commitments: impl IntoIterator>, point: &'a P::Point, values: impl IntoIterator, proof: &Self::Proof, - opening_challenges: &dyn Fn(u64) -> E::Fr, + opening_challenges: &mut ChallengeGenerator, _rng: Option<&mut dyn RngCore>, ) -> Result where @@ -400,7 +402,7 @@ where let mut combined_witness: E::G1Projective = E::G1Projective::zero(); let mut combined_adjusted_witness: E::G1Projective = E::G1Projective::zero(); - Self::accumulate_elems_individual_opening_challenges( + Self::accumulate_elems( &mut combined_comms, &mut combined_witness, &mut combined_adjusted_witness, @@ -423,13 +425,13 @@ where res } - fn batch_check_individual_opening_challenges<'a, R: RngCore>( + fn batch_check<'a, R: RngCore>( vk: &Self::VerifierKey, commitments: impl IntoIterator>, query_set: &QuerySet, values: &Evaluations, proof: &Self::BatchProof, - opening_challenges: &dyn Fn(u64) -> E::Fr, + opening_challenges: &mut ChallengeGenerator, rng: &mut R, ) -> Result where @@ -471,7 +473,7 @@ where values_to_combine.push(*v_i); } - Self::accumulate_elems_individual_opening_challenges( + Self::accumulate_elems( &mut combined_comms, &mut combined_witness, &mut combined_adjusted_witness, @@ -495,16 +497,16 @@ where ) } - fn open_combinations_individual_opening_challenges<'a>( + fn open_combinations<'a>( ck: &Self::CommitterKey, - lc_s: impl IntoIterator>, + linear_combinations: impl IntoIterator>, polynomials: impl IntoIterator>, commitments: impl IntoIterator>, query_set: &QuerySet, - opening_challenges: &dyn Fn(u64) -> E::Fr, + opening_challenges: &mut ChallengeGenerator, rands: impl IntoIterator, rng: Option<&mut dyn RngCore>, - ) -> Result, Self::Error> + ) -> Result, Self::Error> where Self::Randomness: 'a, Self::Commitment: 'a, @@ -522,7 +524,7 @@ where let mut lc_commitments = Vec::new(); let mut lc_info = Vec::new(); - for lc in lc_s { + for lc in linear_combinations { let lc_label = lc.label().clone(); let mut poly = P::zero(); let mut degree_bound = None; @@ -576,7 +578,7 @@ where .map(|((label, d), c)| LabeledCommitment::new(label, c, d)) .collect::>(); - let proof = Self::batch_open_individual_opening_challenges( + let proof = Self::batch_open( ck, lc_polynomials.iter(), lc_commitments.iter(), @@ -590,14 +592,14 @@ where /// Checks that `values` are the true evaluations at `query_set` of the polynomials /// committed in `labeled_commitments`. - fn check_combinations_individual_opening_challenges<'a, R: RngCore>( + fn check_combinations<'a, R: RngCore>( vk: &Self::VerifierKey, - lc_s: impl IntoIterator>, + linear_combinations: impl IntoIterator>, commitments: impl IntoIterator>, - query_set: &QuerySet, - evaluations: &Evaluations, - proof: &BatchLCProof, - opening_challenges: &dyn Fn(u64) -> E::Fr, + eqn_query_set: &QuerySet, + eqn_evaluations: &Evaluations, + proof: &BatchLCProof, + opening_challenges: &mut ChallengeGenerator, rng: &mut R, ) -> Result where @@ -611,8 +613,8 @@ where let mut lc_commitments = Vec::new(); let mut lc_info = Vec::new(); - let mut evaluations = evaluations.clone(); - for lc in lc_s { + let mut evaluations = eqn_evaluations.clone(); + for lc in linear_combinations { let lc_label = lc.label().clone(); let num_polys = lc.len(); @@ -661,10 +663,10 @@ where .map(|((label, d), c)| LabeledCommitment::new(label, c, d)) .collect::>(); - Self::batch_check_individual_opening_challenges( + Self::batch_check( vk, &lc_commitments, - &query_set, + &eqn_query_set, &evaluations, proof, opening_challenges, @@ -682,14 +684,17 @@ mod tests { use ark_ec::PairingEngine; use ark_ff::UniformRand; use ark_poly::{univariate::DensePolynomial as DensePoly, UVPolynomial}; + use ark_sponge::poseidon::PoseidonSponge; use ark_std::rand::rngs::StdRng; type UniPoly_381 = DensePoly<::Fr>; type UniPoly_377 = DensePoly<::Fr>; - type PC = SonicKZG10; - type PC_Bls12_377 = PC; - type PC_Bls12_381 = PC; + type PC = SonicKZG10; + type Sponge_Bls12_377 = PoseidonSponge<::Fr>; + type Sponge_Bls12_381 = PoseidonSponge<::Fr>; + type PC_Bls12_377 = PC; + type PC_Bls12_381 = PC; fn rand_poly( degree: usize, @@ -706,16 +711,18 @@ mod tests { #[test] fn single_poly_test() { use crate::tests::*; - single_poly_test::<_, _, PC_Bls12_377>( + single_poly_test::<_, _, PC_Bls12_377, _>( None, rand_poly::, rand_point::, + poseidon_sponge_for_test, ) .expect("test failed for bls12-377"); - single_poly_test::<_, _, PC_Bls12_381>( + single_poly_test::<_, _, PC_Bls12_381, _>( None, rand_poly::, rand_point::, + poseidon_sponge_for_test, ) .expect("test failed for bls12-381"); } @@ -723,14 +730,16 @@ mod tests { #[test] fn quadratic_poly_degree_bound_multiple_queries_test() { use crate::tests::*; - quadratic_poly_degree_bound_multiple_queries_test::<_, _, PC_Bls12_377>( + quadratic_poly_degree_bound_multiple_queries_test::<_, _, PC_Bls12_377, _>( rand_poly::, rand_point::, + poseidon_sponge_for_test, ) .expect("test failed for bls12-377"); - quadratic_poly_degree_bound_multiple_queries_test::<_, _, PC_Bls12_381>( + quadratic_poly_degree_bound_multiple_queries_test::<_, _, PC_Bls12_381, _>( rand_poly::, rand_point::, + poseidon_sponge_for_test, ) .expect("test failed for bls12-381"); } @@ -738,14 +747,16 @@ mod tests { #[test] fn linear_poly_degree_bound_test() { use crate::tests::*; - linear_poly_degree_bound_test::<_, _, PC_Bls12_377>( + linear_poly_degree_bound_test::<_, _, PC_Bls12_377, _>( rand_poly::, rand_point::, + poseidon_sponge_for_test, ) .expect("test failed for bls12-377"); - linear_poly_degree_bound_test::<_, _, PC_Bls12_381>( + linear_poly_degree_bound_test::<_, _, PC_Bls12_381, _>( rand_poly::, rand_point::, + poseidon_sponge_for_test, ) .expect("test failed for bls12-381"); } @@ -753,14 +764,16 @@ mod tests { #[test] fn single_poly_degree_bound_test() { use crate::tests::*; - single_poly_degree_bound_test::<_, _, PC_Bls12_377>( + single_poly_degree_bound_test::<_, _, PC_Bls12_377, _>( rand_poly::, rand_point::, + poseidon_sponge_for_test, ) .expect("test failed for bls12-377"); - single_poly_degree_bound_test::<_, _, PC_Bls12_381>( + single_poly_degree_bound_test::<_, _, PC_Bls12_381, _>( rand_poly::, rand_point::, + poseidon_sponge_for_test, ) .expect("test failed for bls12-381"); } @@ -768,14 +781,16 @@ mod tests { #[test] fn single_poly_degree_bound_multiple_queries_test() { use crate::tests::*; - single_poly_degree_bound_multiple_queries_test::<_, _, PC_Bls12_377>( + single_poly_degree_bound_multiple_queries_test::<_, _, PC_Bls12_377, _>( rand_poly::, rand_point::, + poseidon_sponge_for_test, ) .expect("test failed for bls12-377"); - single_poly_degree_bound_multiple_queries_test::<_, _, PC_Bls12_381>( + single_poly_degree_bound_multiple_queries_test::<_, _, PC_Bls12_381, _>( rand_poly::, rand_point::, + poseidon_sponge_for_test, ) .expect("test failed for bls12-381"); } @@ -783,14 +798,16 @@ mod tests { #[test] fn two_polys_degree_bound_single_query_test() { use crate::tests::*; - two_polys_degree_bound_single_query_test::<_, _, PC_Bls12_377>( + two_polys_degree_bound_single_query_test::<_, _, PC_Bls12_377, _>( rand_poly::, rand_point::, + poseidon_sponge_for_test, ) .expect("test failed for bls12-377"); - two_polys_degree_bound_single_query_test::<_, _, PC_Bls12_381>( + two_polys_degree_bound_single_query_test::<_, _, PC_Bls12_381, _>( rand_poly::, rand_point::, + poseidon_sponge_for_test, ) .expect("test failed for bls12-381"); } @@ -798,17 +815,19 @@ mod tests { #[test] fn full_end_to_end_test() { use crate::tests::*; - full_end_to_end_test::<_, _, PC_Bls12_377>( + full_end_to_end_test::<_, _, PC_Bls12_377, _>( None, rand_poly::, rand_point::, + poseidon_sponge_for_test, ) .expect("test failed for bls12-377"); println!("Finished bls12-377"); - full_end_to_end_test::<_, _, PC_Bls12_381>( + full_end_to_end_test::<_, _, PC_Bls12_381, _>( None, rand_poly::, rand_point::, + poseidon_sponge_for_test, ) .expect("test failed for bls12-381"); println!("Finished bls12-381"); @@ -817,17 +836,19 @@ mod tests { #[test] fn single_equation_test() { use crate::tests::*; - single_equation_test::<_, _, PC_Bls12_377>( + single_equation_test::<_, _, PC_Bls12_377, _>( None, rand_poly::, rand_point::, + poseidon_sponge_for_test, ) .expect("test failed for bls12-377"); println!("Finished bls12-377"); - single_equation_test::<_, _, PC_Bls12_381>( + single_equation_test::<_, _, PC_Bls12_381, _>( None, rand_poly::, rand_point::, + poseidon_sponge_for_test, ) .expect("test failed for bls12-381"); println!("Finished bls12-381"); @@ -836,17 +857,19 @@ mod tests { #[test] fn two_equation_test() { use crate::tests::*; - two_equation_test::<_, _, PC_Bls12_377>( + two_equation_test::<_, _, PC_Bls12_377, _>( None, rand_poly::, rand_point::, + poseidon_sponge_for_test, ) .expect("test failed for bls12-377"); println!("Finished bls12-377"); - two_equation_test::<_, _, PC_Bls12_381>( + two_equation_test::<_, _, PC_Bls12_381, _>( None, rand_poly::, rand_point::, + poseidon_sponge_for_test, ) .expect("test failed for bls12-381"); println!("Finished bls12-381"); @@ -855,15 +878,17 @@ mod tests { #[test] fn two_equation_degree_bound_test() { use crate::tests::*; - two_equation_degree_bound_test::<_, _, PC_Bls12_377>( + two_equation_degree_bound_test::<_, _, PC_Bls12_377, _>( rand_poly::, rand_point::, + poseidon_sponge_for_test, ) .expect("test failed for bls12-377"); println!("Finished bls12-377"); - two_equation_degree_bound_test::<_, _, PC_Bls12_381>( + two_equation_degree_bound_test::<_, _, PC_Bls12_381, _>( rand_poly::, rand_point::, + poseidon_sponge_for_test, ) .expect("test failed for bls12-381"); println!("Finished bls12-381"); @@ -872,17 +897,19 @@ mod tests { #[test] fn full_end_to_end_equation_test() { use crate::tests::*; - full_end_to_end_equation_test::<_, _, PC_Bls12_377>( + full_end_to_end_equation_test::<_, _, PC_Bls12_377, _>( None, rand_poly::, rand_point::, + poseidon_sponge_for_test, ) .expect("test failed for bls12-377"); println!("Finished bls12-377"); - full_end_to_end_equation_test::<_, _, PC_Bls12_381>( + full_end_to_end_equation_test::<_, _, PC_Bls12_381, _>( None, rand_poly::, rand_point::, + poseidon_sponge_for_test, ) .expect("test failed for bls12-381"); println!("Finished bls12-381"); @@ -892,15 +919,17 @@ mod tests { #[should_panic] fn bad_degree_bound_test() { use crate::tests::*; - bad_degree_bound_test::<_, _, PC_Bls12_377>( + bad_degree_bound_test::<_, _, PC_Bls12_377, _>( rand_poly::, rand_point::, + poseidon_sponge_for_test, ) .expect("test failed for bls12-377"); println!("Finished bls12-377"); - bad_degree_bound_test::<_, _, PC_Bls12_381>( + bad_degree_bound_test::<_, _, PC_Bls12_381, _>( rand_poly::, rand_point::, + poseidon_sponge_for_test, ) .expect("test failed for bls12-381"); println!("Finished bls12-381");