From bab04d8175695cb0d7daf5796d6fbf611414c318 Mon Sep 17 00:00:00 2001 From: Nicholas Ward <npward@berkeley.edu> Date: Thu, 29 Oct 2020 16:10:25 -0700 Subject: [PATCH] Prepared vk/commitment types, and individual opening challenges (#46) Co-authored-by: Pratyush Mishra <pratyushmishra@berkeley.edu> Co-authored-by: weikeng <w.k@berkeley.edu> --- Cargo.toml | 9 +- src/data_structures.rs | 46 ++-- src/ipa_pc/data_structures.rs | 20 ++ src/ipa_pc/mod.rs | 81 ++++--- src/kzg10/data_structures.rs | 66 ++++++ src/kzg10/mod.rs | 6 +- src/lib.rs | 382 ++++++++++++++++++++++--------- src/marlin_pc/data_structures.rs | 95 +++++++- src/marlin_pc/mod.rs | 254 +++++++++++++------- src/sonic_pc/data_structures.rs | 33 ++- src/sonic_pc/mod.rs | 81 ++++--- 11 files changed, 792 insertions(+), 281 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f13bdc4..988c86b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,9 +24,12 @@ edition = "2018" ark-serialize = { git = "https://github.com/arkworks-rs/algebra", default-features = false, features = [ "derive" ] } ark-ff = { git = "https://github.com/arkworks-rs/algebra", default-features = false } ark-ec = { git = "https://github.com/arkworks-rs/algebra", default-features = false } -ark-std = { git = "https://github.com/arkworks-rs/utils", default-features = false } ark-poly = { git = "https://github.com/arkworks-rs/algebra", default-features = false } -bench-utils = { git = "https://github.com/arkworks-rs/utils" } + +ark-std = { git = "https://github.com/arkworks-rs/utils", default-features = false } + +bench-utils = { git = "https://github.com/arkworks-rs/utils", default-features = false } + rand_core = { version = "0.5", default-features = false } digest = "0.8" rayon = { version = "1", optional = true } @@ -52,7 +55,7 @@ incremental = true debug = true [features] -default = ["std", "parallel"] +default = [ "std", "parallel" ] std = [ "ark-ff/std", "ark-ec/std", "ark-poly/std", "ark-std/std", "ark-serialize/std" ] print-trace = [ "bench-utils/print-trace" ] parallel = [ "std", "ark-ff/parallel", "ark-ec/parallel", "ark-poly/parallel", "ark-std/parallel", "rayon" ] diff --git a/src/data_structures.rs b/src/data_structures.rs index c62ae65..2e8e4fd 100644 --- a/src/data_structures.rs +++ b/src/data_structures.rs @@ -1,4 +1,4 @@ -use crate::{Cow, String, Vec}; +use crate::{Rc, String, Vec}; use ark_ff::Field; pub use ark_poly::DensePolynomial as Polynomial; use core::borrow::Borrow; @@ -37,6 +37,13 @@ pub trait PCVerifierKey: Clone + core::fmt::Debug { fn supported_degree(&self) -> usize; } +/// Defines the minimal interface of prepared verifier keys for any polynomial +/// commitment scheme. +pub trait PCPreparedVerifierKey<Unprepared: PCVerifierKey> { + /// prepare + fn prepare(vk: &Unprepared) -> Self; +} + /// Defines the minimal interface of commitments for any polynomial /// commitment scheme. pub trait PCCommitment: Clone + ark_ff::ToBytes { @@ -50,6 +57,13 @@ pub trait PCCommitment: Clone + ark_ff::ToBytes { fn size_in_bytes(&self) -> usize; } +/// Defines the minimal interface of prepared commitments for any polynomial +/// commitment scheme. +pub trait PCPreparedCommitment<UNPREPARED: PCCommitment>: Clone { + /// prepare + fn prepare(comm: &UNPREPARED) -> Self; +} + /// Defines the minimal interface of commitment randomness for any polynomial /// commitment scheme. pub trait PCRandomness: Clone { @@ -74,14 +88,14 @@ pub trait PCProof: Clone + ark_ff::ToBytes { /// maximum number of queries that will be made to it. This latter number determines /// the amount of protection that will be provided to a commitment for this polynomial. #[derive(Debug, Clone)] -pub struct LabeledPolynomial<'a, F: Field> { +pub struct LabeledPolynomial<F: Field> { label: PolynomialLabel, - polynomial: Cow<'a, Polynomial<F>>, + polynomial: Rc<Polynomial<F>>, degree_bound: Option<usize>, hiding_bound: Option<usize>, } -impl<'a, F: Field> core::ops::Deref for LabeledPolynomial<'a, F> { +impl<'a, F: Field> core::ops::Deref for LabeledPolynomial<F> { type Target = Polynomial<F>; fn deref(&self) -> &Self::Target { @@ -89,33 +103,17 @@ impl<'a, F: Field> core::ops::Deref for LabeledPolynomial<'a, F> { } } -impl<'a, F: Field> LabeledPolynomial<'a, F> { - /// Construct a new labeled polynomial by consuming `polynomial`. - pub fn new_owned( - label: PolynomialLabel, - polynomial: Polynomial<F>, - degree_bound: Option<usize>, - hiding_bound: Option<usize>, - ) -> Self { - Self { - label, - polynomial: Cow::Owned(polynomial), - degree_bound, - - hiding_bound, - } - } - +impl<'a, F: Field> LabeledPolynomial<F> { /// Construct a new labeled polynomial. pub fn new( label: PolynomialLabel, - polynomial: &'a Polynomial<F>, + polynomial: Polynomial<F>, degree_bound: Option<usize>, hiding_bound: Option<usize>, ) -> Self { Self { label, - polynomial: Cow::Borrowed(polynomial), + polynomial: Rc::new(polynomial), degree_bound, hiding_bound, } @@ -262,7 +260,7 @@ pub struct LinearCombination<F> { /// The label. pub label: String, /// The linear combination of `(coeff, poly_label)` pairs. - terms: Vec<(F, LCTerm)>, + pub terms: Vec<(F, LCTerm)>, } impl<F: Field> LinearCombination<F> { diff --git a/src/ipa_pc/data_structures.rs b/src/ipa_pc/data_structures.rs index b5efd58..2e1b5c0 100644 --- a/src/ipa_pc/data_structures.rs +++ b/src/ipa_pc/data_structures.rs @@ -72,6 +72,16 @@ impl<G: AffineCurve> PCVerifierKey for VerifierKey<G> { } } +/// Nothing to do to prepare this verifier key (for now). +pub type PreparedVerifierKey<G> = VerifierKey<G>; + +impl<G: AffineCurve> PCPreparedVerifierKey<VerifierKey<G>> for PreparedVerifierKey<G> { + /// prepare `PreparedVerifierKey` from `VerifierKey` + fn prepare(vk: &VerifierKey<G>) -> Self { + vk.clone() + } +} + /// Commitment to a polynomial that optionally enforces a degree bound. #[derive(Derivative)] #[derivative( @@ -124,6 +134,16 @@ impl<G: AffineCurve> ToBytes for Commitment<G> { } } +/// Nothing to do to prepare this commitment (for now). +pub type PreparedCommitment<E> = Commitment<E>; + +impl<G: AffineCurve> PCPreparedCommitment<Commitment<G>> for PreparedCommitment<G> { + /// prepare `PreparedCommitment` from `Commitment` + fn prepare(vk: &Commitment<G>) -> Self { + vk.clone() + } +} + /// `Randomness` hides the polynomial inside a commitment and is outputted by `InnerProductArg::commit`. #[derive(Derivative)] #[derivative( diff --git a/src/ipa_pc/mod.rs b/src/ipa_pc/mod.rs index 1a08a90..36c1285 100644 --- a/src/ipa_pc/mod.rs +++ b/src/ipa_pc/mod.rs @@ -88,7 +88,7 @@ impl<G: AffineCurve, D: Digest> InnerProductArgPC<G, D> { point: G::ScalarField, values: impl IntoIterator<Item = G::ScalarField>, proof: &Proof<G>, - opening_challenge: G::ScalarField, + opening_challenges: &dyn Fn(u64) -> G::ScalarField, ) -> Option<SuccinctCheckPolynomial<G::ScalarField>> { let check_time = start_timer!(|| "Succinct checking"); @@ -100,7 +100,10 @@ impl<G: AffineCurve, D: Digest> InnerProductArgPC<G, D> { let mut combined_commitment_proj = G::Projective::zero(); let mut combined_v = G::ScalarField::zero(); - let mut cur_challenge = opening_challenge; + let mut opening_challenge_counter = 0; + let mut cur_challenge = opening_challenges(opening_challenge_counter); + opening_challenge_counter += 1; + let labeled_commitments = commitments.into_iter(); let values = values.into_iter(); @@ -108,7 +111,8 @@ impl<G: AffineCurve, D: Digest> InnerProductArgPC<G, D> { let commitment = labeled_commitment.commitment(); combined_v += &(cur_challenge * &value); combined_commitment_proj += &labeled_commitment.commitment().comm.mul(cur_challenge); - cur_challenge *= &opening_challenge; + cur_challenge = opening_challenges(opening_challenge_counter); + opening_challenge_counter += 1; let degree_bound = labeled_commitment.degree_bound(); assert_eq!(degree_bound.is_some(), commitment.shifted_comm.is_some()); @@ -119,7 +123,8 @@ impl<G: AffineCurve, D: Digest> InnerProductArgPC<G, D> { combined_commitment_proj += &commitment.shifted_comm.unwrap().mul(cur_challenge); } - cur_challenge *= &opening_challenge; + cur_challenge = opening_challenges(opening_challenge_counter); + opening_challenge_counter += 1; } let mut combined_commitment = combined_commitment_proj.into_affine(); @@ -306,7 +311,9 @@ impl<G: AffineCurve, D: Digest> PolynomialCommitment<G::ScalarField> for InnerPr type UniversalParams = UniversalParams<G>; type CommitterKey = CommitterKey<G>; type VerifierKey = VerifierKey<G>; + type PreparedVerifierKey = PreparedVerifierKey<G>; type Commitment = Commitment<G>; + type PreparedCommitment = PreparedCommitment<G>; type Randomness = Randomness<G>; type Proof = Proof<G>; type BatchProof = Vec<Self::Proof>; @@ -372,7 +379,7 @@ impl<G: AffineCurve, D: Digest> PolynomialCommitment<G::ScalarField> for InnerPr /// Outputs a commitment to `polynomial`. fn commit<'a>( ck: &Self::CommitterKey, - polynomials: impl IntoIterator<Item = &'a LabeledPolynomial<'a, G::ScalarField>>, + polynomials: impl IntoIterator<Item = &'a LabeledPolynomial<G::ScalarField>>, rng: Option<&mut dyn RngCore>, ) -> Result< ( @@ -439,12 +446,12 @@ impl<G: AffineCurve, D: Digest> PolynomialCommitment<G::ScalarField> for InnerPr Ok((comms, rands)) } - fn open<'a>( + fn open_individual_opening_challenges<'a>( ck: &Self::CommitterKey, - labeled_polynomials: impl IntoIterator<Item = &'a LabeledPolynomial<'a, G::ScalarField>>, + labeled_polynomials: impl IntoIterator<Item = &'a LabeledPolynomial<G::ScalarField>>, commitments: impl IntoIterator<Item = &'a LabeledCommitment<Self::Commitment>>, point: G::ScalarField, - opening_challenge: G::ScalarField, + opening_challenges: &dyn Fn(u64) -> G::ScalarField, rands: impl IntoIterator<Item = &'a Self::Randomness>, rng: Option<&mut dyn RngCore>, ) -> Result<Self::Proof, Self::Error> @@ -463,7 +470,11 @@ impl<G: AffineCurve, D: Digest> PolynomialCommitment<G::ScalarField> for InnerPr let comms_iter = commitments.into_iter(); let combine_time = start_timer!(|| "Combining polynomials, randomness, and commitments."); - let mut cur_challenge = opening_challenge; + + let mut opening_challenge_counter = 0; + let mut cur_challenge = opening_challenges(opening_challenge_counter); + opening_challenge_counter += 1; + for (labeled_polynomial, (labeled_commitment, randomness)) in polys_iter.zip(comms_iter.zip(rands_iter)) { @@ -484,7 +495,8 @@ impl<G: AffineCurve, D: Digest> PolynomialCommitment<G::ScalarField> for InnerPr combined_rand += &(cur_challenge * &randomness.rand); } - cur_challenge *= &opening_challenge; + cur_challenge = opening_challenges(opening_challenge_counter); + opening_challenge_counter += 1; let has_degree_bound = degree_bound.is_some(); @@ -517,7 +529,8 @@ impl<G: AffineCurve, D: Digest> PolynomialCommitment<G::ScalarField> for InnerPr } } - cur_challenge *= &opening_challenge; + cur_challenge = opening_challenges(opening_challenge_counter); + opening_challenge_counter += 1; } end_timer!(combine_time); @@ -677,13 +690,13 @@ impl<G: AffineCurve, D: Digest> PolynomialCommitment<G::ScalarField> for InnerPr }) } - fn check<'a>( + fn check_individual_opening_challenges<'a>( vk: &Self::VerifierKey, commitments: impl IntoIterator<Item = &'a LabeledCommitment<Self::Commitment>>, point: G::ScalarField, values: impl IntoIterator<Item = G::ScalarField>, proof: &Self::Proof, - opening_challenge: G::ScalarField, + opening_challenges: &dyn Fn(u64) -> G::ScalarField, _rng: Option<&mut dyn RngCore>, ) -> Result<bool, Self::Error> where @@ -707,7 +720,7 @@ impl<G: AffineCurve, D: Digest> PolynomialCommitment<G::ScalarField> for InnerPr } let check_poly = - Self::succinct_check(vk, commitments, point, values, proof, opening_challenge); + Self::succinct_check(vk, commitments, point, values, proof, opening_challenges); if check_poly.is_none() { return Ok(false); @@ -728,13 +741,13 @@ impl<G: AffineCurve, D: Digest> PolynomialCommitment<G::ScalarField> for InnerPr Ok(true) } - fn batch_check<'a, R: RngCore>( + fn batch_check_individual_opening_challenges<'a, R: RngCore>( vk: &Self::VerifierKey, commitments: impl IntoIterator<Item = &'a LabeledCommitment<Self::Commitment>>, query_set: &QuerySet<G::ScalarField>, values: &Evaluations<G::ScalarField>, proof: &Self::BatchProof, - opening_challenge: G::ScalarField, + opening_challenges: &dyn Fn(u64) -> G::ScalarField, rng: &mut R, ) -> Result<bool, Self::Error> where @@ -743,9 +756,11 @@ impl<G: AffineCurve, D: Digest> PolynomialCommitment<G::ScalarField> for InnerPr let commitments: BTreeMap<_, _> = commitments.into_iter().map(|c| (c.label(), c)).collect(); let mut query_to_labels_map = BTreeMap::new(); - for (label, point) in query_set.iter() { - let labels = query_to_labels_map.entry(point).or_insert(BTreeSet::new()); - labels.insert(label); + for (label, (point_label, point)) in query_set.iter() { + let labels = query_to_labels_map + .entry(point_label) + .or_insert((point, BTreeSet::new())); + labels.1.insert(label); } assert_eq!(proof.len(), query_to_labels_map.len()); @@ -755,7 +770,7 @@ impl<G: AffineCurve, D: Digest> PolynomialCommitment<G::ScalarField> for InnerPr let mut combined_check_poly = Polynomial::zero(); let mut combined_final_key = G::Projective::zero(); - for ((query, labels), p) in query_to_labels_map.into_iter().zip(proof) { + for ((_point_label, (point, labels)), p) in query_to_labels_map.into_iter().zip(proof) { let lc_time = start_timer!(|| format!("Randomly combining {} commitments", labels.len())); let mut comms: Vec<&'_ LabeledCommitment<_>> = Vec::new(); @@ -766,7 +781,7 @@ impl<G: AffineCurve, D: Digest> PolynomialCommitment<G::ScalarField> for InnerPr })?; let v_i = values - .get(&(label.clone(), *query)) + .get(&(label.clone(), *point)) .ok_or(Error::MissingEvaluation { label: label.to_string(), })?; @@ -778,10 +793,10 @@ impl<G: AffineCurve, D: Digest> PolynomialCommitment<G::ScalarField> for InnerPr let check_poly = Self::succinct_check( vk, comms.into_iter(), - *query, + *point, vals.into_iter(), p, - opening_challenge, + opening_challenges, ); if check_poly.is_none() { @@ -813,13 +828,13 @@ impl<G: AffineCurve, D: Digest> PolynomialCommitment<G::ScalarField> for InnerPr Ok(true) } - fn open_combinations<'a>( + fn open_combinations_individual_opening_challenges<'a>( ck: &Self::CommitterKey, lc_s: impl IntoIterator<Item = &'a LinearCombination<G::ScalarField>>, - polynomials: impl IntoIterator<Item = &'a LabeledPolynomial<'a, G::ScalarField>>, + polynomials: impl IntoIterator<Item = &'a LabeledPolynomial<G::ScalarField>>, commitments: impl IntoIterator<Item = &'a LabeledCommitment<Self::Commitment>>, query_set: &QuerySet<G::ScalarField>, - opening_challenge: G::ScalarField, + opening_challenges: &dyn Fn(u64) -> G::ScalarField, rands: impl IntoIterator<Item = &'a Self::Randomness>, rng: Option<&mut dyn RngCore>, ) -> Result<BatchLCProof<G::ScalarField, Self>, Self::Error> @@ -891,7 +906,7 @@ impl<G: AffineCurve, D: Digest> PolynomialCommitment<G::ScalarField> for InnerPr } let lc_poly = - LabeledPolynomial::new_owned(lc_label.clone(), poly, degree_bound, hiding_bound); + LabeledPolynomial::new(lc_label.clone(), poly, degree_bound, hiding_bound); lc_polynomials.push(lc_poly); lc_randomness.push(Randomness { rand: combined_rand, @@ -908,12 +923,12 @@ impl<G: AffineCurve, D: Digest> PolynomialCommitment<G::ScalarField> for InnerPr let lc_commitments = Self::construct_labeled_commitments(&lc_info, &lc_commitments); - let proof = Self::batch_open( + let proof = Self::batch_open_individual_opening_challenges( ck, lc_polynomials.iter(), lc_commitments.iter(), &query_set, - opening_challenge, + opening_challenges, lc_randomness.iter(), rng, )?; @@ -922,14 +937,14 @@ impl<G: AffineCurve, D: Digest> PolynomialCommitment<G::ScalarField> for InnerPr /// Checks that `values` are the true evaluations at `query_set` of the polynomials /// committed in `labeled_commitments`. - fn check_combinations<'a, R: RngCore>( + fn check_combinations_individual_opening_challenges<'a, R: RngCore>( vk: &Self::VerifierKey, lc_s: impl IntoIterator<Item = &'a LinearCombination<G::ScalarField>>, commitments: impl IntoIterator<Item = &'a LabeledCommitment<Self::Commitment>>, query_set: &QuerySet<G::ScalarField>, evaluations: &Evaluations<G::ScalarField>, proof: &BatchLCProof<G::ScalarField, Self>, - opening_challenge: G::ScalarField, + opening_challenges: &dyn Fn(u64) -> G::ScalarField, rng: &mut R, ) -> Result<bool, Self::Error> where @@ -996,13 +1011,13 @@ impl<G: AffineCurve, D: Digest> PolynomialCommitment<G::ScalarField> for InnerPr let lc_commitments = Self::construct_labeled_commitments(&lc_info, &lc_commitments); - Self::batch_check( + Self::batch_check_individual_opening_challenges( vk, &lc_commitments, &query_set, &evaluations, proof, - opening_challenge, + opening_challenges, rng, ) } diff --git a/src/kzg10/data_structures.rs b/src/kzg10/data_structures.rs index 0d11799..62eb2df 100644 --- a/src/kzg10/data_structures.rs +++ b/src/kzg10/data_structures.rs @@ -1,6 +1,7 @@ use crate::*; use ark_ec::{AffineCurve, PairingEngine, ProjectiveCurve}; use ark_ff::{PrimeField, ToBytes, Zero}; +use ark_std::borrow::Cow; use core::ops::{Add, AddAssign}; /// `UniversalParams` are the universal parameters for the KZG10 scheme. @@ -86,6 +87,39 @@ impl<E: PairingEngine> ToBytes for VerifierKey<E> { } } +/// `PreparedVerifierKey` is the fully prepared version for checking evaluation proofs for a given commitment. +/// We omit gamma here for simplicity. +#[derive(Derivative)] +#[derivative(Default(bound = ""), Clone(bound = ""), Debug(bound = ""))] +pub struct PreparedVerifierKey<E: PairingEngine> { + /// The generator of G1, prepared for power series. + pub prepared_g: Vec<E::G1Affine>, + /// The generator of G2, prepared for use in pairings. + pub prepared_h: E::G2Prepared, + /// \beta times the above generator of G2, prepared for use in pairings. + pub prepared_beta_h: E::G2Prepared, +} + +impl<E: PairingEngine> PreparedVerifierKey<E> { + /// prepare `PreparedVerifierKey` from `VerifierKey` + pub fn prepare(vk: &VerifierKey<E>) -> Self { + let supported_bits = E::Fr::size_in_bits(); + + let mut prepared_g = Vec::<E::G1Affine>::new(); + let mut g = E::G1Projective::from(vk.g.clone()); + for _ in 0..supported_bits { + prepared_g.push(g.clone().into()); + g.double_in_place(); + } + + Self { + prepared_g, + prepared_h: vk.prepared_h.clone(), + prepared_beta_h: vk.prepared_beta_h.clone(), + } + } +} + /// `Commitment` commits to a polynomial. It is output by `KZG10::commit`. #[derive(Derivative)] #[derivative( @@ -133,6 +167,38 @@ impl<'a, E: PairingEngine> AddAssign<(E::Fr, &'a Commitment<E>)> for Commitment< } } +/// `PreparedCommitment` commits to a polynomial and prepares for mul_bits. +#[derive(Derivative)] +#[derivative( + Default(bound = ""), + Hash(bound = ""), + Clone(bound = ""), + Debug(bound = ""), + PartialEq(bound = ""), + Eq(bound = "") +)] +pub struct PreparedCommitment<E: PairingEngine>( + /// The commitment is a group element. + pub Vec<E::G1Affine>, +); + +impl<E: PairingEngine> PreparedCommitment<E> { + /// prepare `PreparedCommitment` from `Commitment` + pub fn prepare(comm: &Commitment<E>) -> Self { + let mut prepared_comm = Vec::<E::G1Affine>::new(); + let mut cur = E::G1Projective::from(comm.0.clone()); + + let supported_bits = E::Fr::size_in_bits(); + + for _ in 0..supported_bits { + prepared_comm.push(cur.clone().into()); + cur.double_in_place(); + } + + Self { 0: prepared_comm } + } +} + /// `Randomness` hides the polynomial inside a commitment. It is output by `KZG10::commit`. #[derive(Derivative)] #[derivative( diff --git a/src/kzg10/mod.rs b/src/kzg10/mod.rs index 5da4002..f07c65e 100644 --- a/src/kzg10/mod.rs +++ b/src/kzg10/mod.rs @@ -421,7 +421,7 @@ impl<E: PairingEngine> KZG10<E> { supported_degree: usize, max_degree: usize, enforced_degree_bounds: Option<&[usize]>, - p: &'a LabeledPolynomial<'a, E::Fr>, + p: &'a LabeledPolynomial<E::Fr>, ) -> Result<(), Error> { if let Some(bound) = p.degree_bound() { let enforced_degree_bounds = @@ -494,8 +494,8 @@ mod tests { .collect(); let powers = Powers { - powers_of_g: Cow::Owned(powers_of_g), - powers_of_gamma_g: Cow::Owned(powers_of_gamma_g), + powers_of_g: ark_std::borrow::Cow::Owned(powers_of_g), + powers_of_gamma_g: ark_std::borrow::Cow::Owned(powers_of_gamma_g), }; let vk = VerifierKey { g: pp.powers_of_g[0], diff --git a/src/lib.rs b/src/lib.rs index 581a4de..4be0f24 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,12 +17,12 @@ extern crate bench_utils; use ark_ff::Field; pub use ark_poly::DensePolynomial as Polynomial; +use core::iter::FromIterator; use rand_core::RngCore; use ark_std::{ - borrow::Cow, collections::{BTreeMap, BTreeSet}, - iter::FromIterator, + rc::Rc, string::{String, ToString}, vec::Vec, }; @@ -44,6 +44,11 @@ macro_rules! eprintln { () => {}; ($($arg: tt)*) => {}; } +#[cfg(not(feature = "std"))] +macro_rules! println { + () => {}; + ($($arg: tt)*) => {}; +} /// The core [[KZG10]][kzg] construction. /// /// [kzg]: http://cacr.uwaterloo.ca/techreports/2010/cacr2010-10.pdf @@ -77,10 +82,11 @@ pub mod sonic_pc; pub mod ipa_pc; /// `QuerySet` is the set of queries that are to be made to a set of labeled polynomials/equations -/// `p` that have previously been committed to. Each element of a `QuerySet` is a `(label, query)` -/// pair, where `label` is the label of a polynomial in `p`, and `query` is the field element +/// `p` that have previously been committed to. Each element of a `QuerySet` is a pair of +/// `(label, (point_label, point))`, where `label` is the label of a polynomial in `p`, +/// `point_label` is the label for the point (e.g., "beta"), and and `point` is the field element /// that `p[label]` is to be queried at. -pub type QuerySet<'a, F> = BTreeSet<(String, F)>; +pub type QuerySet<'a, F> = BTreeSet<(String, (String, F))>; /// `Evaluations` is the result of querying a set of labeled polynomials or equations /// `p` at a `QuerySet` `Q`. It maps each element of `Q` to the resulting evaluation. @@ -89,6 +95,7 @@ pub type QuerySet<'a, F> = BTreeSet<(String, F)>; pub type Evaluations<'a, F> = BTreeMap<(String, F), F>; /// A proof of satisfaction of linear combinations. +#[derive(Clone)] pub struct BatchLCProof<F: Field, PC: PolynomialCommitment<F>> { /// Evaluation proof. pub proof: PC::BatchProof, @@ -109,8 +116,12 @@ pub trait PolynomialCommitment<F: Field>: Sized { type CommitterKey: PCCommitterKey; /// The verifier key for the scheme; used to check an evaluation proof. type VerifierKey: PCVerifierKey; + /// The prepared verifier key for the scheme; used to check an evaluation proof. + type PreparedVerifierKey: PCPreparedVerifierKey<Self::VerifierKey> + Clone; /// The commitment to a polynomial. - type Commitment: PCCommitment; + type Commitment: PCCommitment + Default; + /// The prepared commitment to a polynomial. + type PreparedCommitment: PCPreparedCommitment<Self::Commitment>; /// The commitment randomness. type Randomness: PCRandomness; /// The evaluation proof for a single point. @@ -147,7 +158,7 @@ pub trait PolynomialCommitment<F: Field>: Sized { /// polynomial will have the corresponding degree bound enforced. fn commit<'a>( ck: &Self::CommitterKey, - polynomials: impl IntoIterator<Item = &'a LabeledPolynomial<'a, F>>, + polynomials: impl IntoIterator<Item = &'a LabeledPolynomial<F>>, rng: Option<&mut dyn RngCore>, ) -> Result< ( @@ -161,7 +172,7 @@ pub trait PolynomialCommitment<F: Field>: Sized { /// of the polynomials at the query point. fn open<'a>( ck: &Self::CommitterKey, - labeled_polynomials: impl IntoIterator<Item = &'a LabeledPolynomial<'a, F>>, + labeled_polynomials: impl IntoIterator<Item = &'a LabeledPolynomial<F>>, commitments: impl IntoIterator<Item = &'a LabeledCommitment<Self::Commitment>>, point: F, opening_challenge: F, @@ -170,13 +181,25 @@ pub trait PolynomialCommitment<F: Field>: Sized { ) -> Result<Self::Proof, Self::Error> where Self::Randomness: 'a, - Self::Commitment: '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<Item = &'a LabeledPolynomial<'a, F>>, + labeled_polynomials: impl IntoIterator<Item = &'a LabeledPolynomial<F>>, commitments: impl IntoIterator<Item = &'a LabeledCommitment<Self::Commitment>>, query_set: &QuerySet<F>, opening_challenge: F, @@ -187,62 +210,16 @@ pub trait PolynomialCommitment<F: Field>: Sized { Self::Randomness: 'a, Self::Commitment: 'a, { - let rng = &mut crate::optional_rng::OptionalRng(rng); - let poly_rand_comm: BTreeMap<_, _> = labeled_polynomials - .into_iter() - .zip(rands) - .zip(commitments.into_iter()) - .map(|((poly, r), comm)| (poly.label(), (poly, r, comm))) - .collect(); - - let open_time = start_timer!(|| format!( - "Opening {} polynomials at query set of size {}", - poly_rand_comm.len(), - query_set.len(), - )); - - let mut query_to_labels_map = BTreeMap::new(); - - for (label, point) in query_set.iter() { - let labels = query_to_labels_map.entry(point).or_insert(BTreeSet::new()); - labels.insert(label); - } - - let mut proofs = Vec::new(); - for (query, labels) in query_to_labels_map.into_iter() { - let mut query_polys: Vec<&'a LabeledPolynomial<'a, _>> = Vec::new(); - let mut query_rands: Vec<&'a Self::Randomness> = Vec::new(); - let mut query_comms: Vec<&'a LabeledCommitment<Self::Commitment>> = Vec::new(); - - for label in labels { - let (polynomial, rand, comm) = - poly_rand_comm.get(label).ok_or(Error::MissingPolynomial { - label: label.to_string(), - })?; - - query_polys.push(polynomial); - query_rands.push(rand); - query_comms.push(comm); - } - - let proof_time = start_timer!(|| "Creating proof"); - let proof = Self::open( - ck, - query_polys, - query_comms, - *query, - opening_challenge, - query_rands, - Some(rng), - )?; - - end_timer!(proof_time); - - proofs.push(proof); - } - end_timer!(open_time); - - Ok(proofs.into()) + 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 @@ -257,7 +234,19 @@ pub trait PolynomialCommitment<F: Field>: Sized { rng: Option<&mut dyn RngCore>, ) -> Result<bool, Self::Error> where - Self::Commitment: 'a; + 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`. @@ -270,14 +259,126 @@ pub trait PolynomialCommitment<F: Field>: Sized { opening_challenge: F, rng: &mut R, ) -> Result<bool, Self::Error> + 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<Item = &'a LinearCombination<F>>, + polynomials: impl IntoIterator<Item = &'a LabeledPolynomial<F>>, + commitments: impl IntoIterator<Item = &'a LabeledCommitment<Self::Commitment>>, + query_set: &QuerySet<F>, + opening_challenge: F, + rands: impl IntoIterator<Item = &'a Self::Randomness>, + rng: Option<&mut dyn RngCore>, + ) -> Result<BatchLCProof<F, Self>, Self::Error> + where + 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<Item = &'a LinearCombination<F>>, + commitments: impl IntoIterator<Item = &'a LabeledCommitment<Self::Commitment>>, + eqn_query_set: &QuerySet<F>, + eqn_evaluations: &Evaluations<F>, + proof: &BatchLCProof<F, Self>, + opening_challenge: F, + rng: &mut R, + ) -> Result<bool, Self::Error> + 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>( + ck: &Self::CommitterKey, + labeled_polynomials: impl IntoIterator<Item = &'a LabeledPolynomial<F>>, + commitments: impl IntoIterator<Item = &'a LabeledCommitment<Self::Commitment>>, + point: F, + opening_challenges: &dyn Fn(u64) -> F, + rands: impl IntoIterator<Item = &'a Self::Randomness>, + rng: Option<&mut dyn RngCore>, + ) -> Result<Self::Proof, Self::Error> + where + Self::Randomness: 'a, + Self::Commitment: 'a; + + /// check but with individual challenges + fn check_individual_opening_challenges<'a>( + vk: &Self::VerifierKey, + commitments: impl IntoIterator<Item = &'a LabeledCommitment<Self::Commitment>>, + point: F, + values: impl IntoIterator<Item = F>, + proof: &Self::Proof, + opening_challenges: &dyn Fn(u64) -> F, + rng: Option<&mut dyn RngCore>, + ) -> Result<bool, Self::Error> + where + Self::Commitment: 'a; + + /// batch_check but with individual challenges + fn batch_check_individual_opening_challenges<'a, R: RngCore>( + vk: &Self::VerifierKey, + commitments: impl IntoIterator<Item = &'a LabeledCommitment<Self::Commitment>>, + query_set: &QuerySet<F>, + evaluations: &Evaluations<F>, + proof: &Self::BatchProof, + opening_challenges: &dyn Fn(u64) -> F, + rng: &mut R, + ) -> Result<bool, Self::Error> where Self::Commitment: 'a, { let commitments: BTreeMap<_, _> = commitments.into_iter().map(|c| (c.label(), c)).collect(); let mut query_to_labels_map = BTreeMap::new(); - for (label, point) in query_set.iter() { - let labels = query_to_labels_map.entry(point).or_insert(BTreeSet::new()); - labels.insert(label); + for (label, (point_label, point)) in query_set.iter() { + let labels = query_to_labels_map + .entry(point_label) + .or_insert((point, BTreeSet::new())); + labels.1.insert(label); } // Implicit assumption: proofs are order in same manner as queries in @@ -286,7 +387,8 @@ pub trait PolynomialCommitment<F: Field>: Sized { assert_eq!(proofs.len(), query_to_labels_map.len()); let mut result = true; - for ((query, labels), proof) in query_to_labels_map.into_iter().zip(proofs) { + for ((_point_label, (point, labels)), proof) in query_to_labels_map.into_iter().zip(proofs) + { let mut comms: Vec<&'_ LabeledCommitment<_>> = Vec::new(); let mut values = Vec::new(); for label in labels.into_iter() { @@ -296,7 +398,7 @@ pub trait PolynomialCommitment<F: Field>: Sized { let v_i = evaluations - .get(&(label.clone(), *query)) + .get(&(label.clone(), *point)) .ok_or(Error::MissingEvaluation { label: label.to_string(), })?; @@ -306,13 +408,13 @@ pub trait PolynomialCommitment<F: Field>: Sized { } let proof_time = start_timer!(|| "Checking per-query proof"); - result &= Self::check( + result &= Self::check_individual_opening_challenges( vk, comms, - *query, + *point, values, &proof, - opening_challenge, + opening_challenges, Some(rng), )?; end_timer!(proof_time); @@ -320,16 +422,14 @@ pub trait PolynomialCommitment<F: Field>: Sized { Ok(result) } - /// 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>( + /// open_combinations but with individual challenges + fn open_combinations_individual_opening_challenges<'a>( ck: &Self::CommitterKey, linear_combinations: impl IntoIterator<Item = &'a LinearCombination<F>>, - polynomials: impl IntoIterator<Item = &'a LabeledPolynomial<'a, F>>, + polynomials: impl IntoIterator<Item = &'a LabeledPolynomial<F>>, commitments: impl IntoIterator<Item = &'a LabeledCommitment<Self::Commitment>>, query_set: &QuerySet<F>, - opening_challenge: F, + opening_challenges: &dyn Fn(u64) -> F, rands: impl IntoIterator<Item = &'a Self::Randomness>, rng: Option<&mut dyn RngCore>, ) -> Result<BatchLCProof<F, Self>, Self::Error> @@ -342,12 +442,12 @@ pub trait PolynomialCommitment<F: Field>: 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( + let proof = Self::batch_open_individual_opening_challenges( ck, polynomials, commitments, &poly_query_set, - opening_challenge, + opening_challenges, rands, rng, )?; @@ -357,16 +457,15 @@ pub trait PolynomialCommitment<F: Field>: Sized { }) } - /// 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>( + /// check_combinations with individual challenges + fn check_combinations_individual_opening_challenges<'a, R: RngCore>( vk: &Self::VerifierKey, linear_combinations: impl IntoIterator<Item = &'a LinearCombination<F>>, commitments: impl IntoIterator<Item = &'a LabeledCommitment<Self::Commitment>>, eqn_query_set: &QuerySet<F>, eqn_evaluations: &Evaluations<F>, proof: &BatchLCProof<F, Self>, - opening_challenge: F, + opening_challenges: &dyn Fn(u64) -> F, rng: &mut R, ) -> Result<bool, Self::Error> where @@ -377,10 +476,15 @@ pub trait PolynomialCommitment<F: Field>: Sized { let lc_s = BTreeMap::from_iter(linear_combinations.into_iter().map(|lc| (lc.label(), lc))); let poly_query_set = lc_query_set_to_poly_query_set(lc_s.values().copied(), eqn_query_set); - let poly_evals = - Evaluations::from_iter(poly_query_set.iter().cloned().zip(evals.clone().unwrap())); + let poly_evals = Evaluations::from_iter( + poly_query_set + .iter() + .map(|(_, point)| point) + .cloned() + .zip(evals.clone().unwrap()), + ); - for &(ref lc_label, point) in eqn_query_set { + for &(ref lc_label, (_, point)) in eqn_query_set { if let Some(lc) = lc_s.get(lc_label) { let claimed_rhs = *eqn_evaluations.get(&(lc_label.clone(), point)).ok_or( Error::MissingEvaluation { @@ -407,13 +511,13 @@ pub trait PolynomialCommitment<F: Field>: Sized { } } - let pc_result = Self::batch_check( + let pc_result = Self::batch_check_individual_opening_challenges( vk, commitments, &poly_query_set, &poly_evals, proof, - opening_challenge, + opening_challenges, rng, )?; if !pc_result { @@ -423,16 +527,90 @@ pub trait PolynomialCommitment<F: Field>: Sized { Ok(true) } + + /// batch_open with individual challenges + fn batch_open_individual_opening_challenges<'a>( + ck: &Self::CommitterKey, + labeled_polynomials: impl IntoIterator<Item = &'a LabeledPolynomial<F>>, + commitments: impl IntoIterator<Item = &'a LabeledCommitment<Self::Commitment>>, + query_set: &QuerySet<F>, + opening_challenges: &dyn Fn(u64) -> F, + rands: impl IntoIterator<Item = &'a Self::Randomness>, + rng: Option<&mut dyn RngCore>, + ) -> Result<Self::BatchProof, Self::Error> + where + Self::Randomness: 'a, + Self::Commitment: 'a, + { + let rng = &mut crate::optional_rng::OptionalRng(rng); + let poly_rand_comm: BTreeMap<_, _> = labeled_polynomials + .into_iter() + .zip(rands) + .zip(commitments.into_iter()) + .map(|((poly, r), comm)| (poly.label(), (poly, r, comm))) + .collect(); + + let open_time = start_timer!(|| format!( + "Opening {} polynomials at query set of size {}", + poly_rand_comm.len(), + query_set.len(), + )); + + let mut query_to_labels_map = BTreeMap::new(); + + for (label, (point_label, point)) in query_set.iter() { + let labels = query_to_labels_map + .entry(point_label) + .or_insert((point, BTreeSet::new())); + labels.1.insert(label); + } + + let mut proofs = Vec::new(); + for (_point_label, (point, labels)) in query_to_labels_map.into_iter() { + let mut query_polys: Vec<&'a LabeledPolynomial<_>> = Vec::new(); + let mut query_rands: Vec<&'a Self::Randomness> = Vec::new(); + let mut query_comms: Vec<&'a LabeledCommitment<Self::Commitment>> = Vec::new(); + + for label in labels { + let (polynomial, rand, comm) = + poly_rand_comm.get(label).ok_or(Error::MissingPolynomial { + label: label.to_string(), + })?; + + query_polys.push(polynomial); + query_rands.push(rand); + query_comms.push(comm); + } + + let proof_time = start_timer!(|| "Creating proof"); + let proof = Self::open_individual_opening_challenges( + ck, + query_polys, + query_comms, + *point, + opening_challenges, + query_rands, + Some(rng), + )?; + + end_timer!(proof_time); + + proofs.push(proof); + } + end_timer!(open_time); + + Ok(proofs.into()) + } } /// Evaluate the given polynomials at `query_set`. pub fn evaluate_query_set<'a, F: Field>( - polys: impl IntoIterator<Item = &'a LabeledPolynomial<'a, F>>, + polys: impl IntoIterator<Item = &'a LabeledPolynomial<F>>, query_set: &QuerySet<'a, F>, ) -> Evaluations<'a, F> { let polys = BTreeMap::from_iter(polys.into_iter().map(|p| (p.label(), p))); let mut evaluations = Evaluations::new(); - for (label, point) in query_set { + for (label, (_, point)) in query_set { let poly = polys .get(label) .expect("polynomial in evaluated lc is not found"); @@ -449,11 +627,11 @@ fn lc_query_set_to_poly_query_set<'a, F: 'a + Field>( let mut poly_query_set = QuerySet::new(); let lc_s = linear_combinations.into_iter().map(|lc| (lc.label(), lc)); let linear_combinations = BTreeMap::from_iter(lc_s); - for (lc_label, point) in query_set { + for (lc_label, (point_label, point)) in query_set { if let Some(lc) = linear_combinations.get(lc_label) { for (_, poly_label) in lc.iter().filter(|(_, l)| !l.is_one()) { if let LCTerm::PolyLabel(l) = poly_label { - poly_query_set.insert((l.into(), *point)); + poly_query_set.insert((l.into(), (point_label.clone(), *point))); } } } @@ -507,7 +685,7 @@ pub mod tests { let hiding_bound = Some(1); degree_bounds.push(degree_bound); - polynomials.push(LabeledPolynomial::new_owned( + polynomials.push(LabeledPolynomial::new( label, poly, Some(degree_bound), @@ -536,7 +714,7 @@ pub mod tests { let mut values = Evaluations::new(); let point = F::rand(rng); for (i, label) in labels.iter().enumerate() { - query_set.insert((label.clone(), point)); + query_set.insert((label.clone(), (format!("{}", i), point))); let value = polynomials[i].evaluate(point); values.insert((label.clone(), point), value); } @@ -628,7 +806,7 @@ pub mod tests { }; println!("Hiding bound: {:?}", hiding_bound); - polynomials.push(LabeledPolynomial::new_owned( + polynomials.push(LabeledPolynomial::new( label, poly, degree_bound, @@ -660,7 +838,7 @@ pub mod tests { for _ in 0..num_points_in_query_set { let point = F::rand(rng); for (i, label) in labels.iter().enumerate() { - query_set.insert((label.clone(), point)); + query_set.insert((label.clone(), (format!("{}", i), point))); let value = polynomials[i].evaluate(point); values.insert((label.clone(), point), value); } @@ -767,7 +945,7 @@ pub mod tests { }; println!("Hiding bound: {:?}", hiding_bound); - polynomials.push(LabeledPolynomial::new_owned( + polynomials.push(LabeledPolynomial::new( label, poly, degree_bound, @@ -823,7 +1001,7 @@ pub mod tests { if !lc.is_empty() { linear_combinations.push(lc); // Insert query - query_set.insert((label.clone(), point)); + query_set.insert((label.clone(), (format!("{}", i), point))); } } } diff --git a/src/marlin_pc/data_structures.rs b/src/marlin_pc/data_structures.rs index 68d0096..c2ae690 100644 --- a/src/marlin_pc/data_structures.rs +++ b/src/marlin_pc/data_structures.rs @@ -1,6 +1,9 @@ -use crate::{PCCommitment, PCCommitterKey, PCRandomness, PCVerifierKey, Vec}; -use ark_ec::PairingEngine; -use ark_ff::ToBytes; +use crate::{ + PCCommitment, PCCommitterKey, PCPreparedCommitment, PCPreparedVerifierKey, PCRandomness, + PCVerifierKey, Vec, +}; +use ark_ec::{PairingEngine, ProjectiveCurve}; +use ark_ff::{PrimeField, ToBytes}; use core::ops::{Add, AddAssign}; use rand_core::RngCore; @@ -143,6 +146,64 @@ impl<E: PairingEngine> ToBytes for VerifierKey<E> { } } +/// `PreparedVerifierKey` is used to check evaluation proofs for a given commitment. +#[derive(Derivative)] +#[derivative(Clone(bound = ""), Debug(bound = ""))] +pub struct PreparedVerifierKey<E: PairingEngine> { + /// The verification key for the underlying KZG10 scheme. + pub prepared_vk: kzg10::PreparedVerifierKey<E>, + /// Information required to enforce degree bounds. Each pair + /// is of the form `(degree_bound, shifting_advice)`. + /// This is `None` if `self` does not support enforcing any degree bounds. + pub prepared_degree_bounds_and_shift_powers: Option<Vec<(usize, Vec<E::G1Affine>)>>, + /// The maximum degree supported by the `UniversalParams` `self` was derived + /// from. + pub max_degree: usize, + /// The maximum degree supported by the trimmed parameters that `self` is + /// a part of. + pub supported_degree: usize, +} + +impl<E: PairingEngine> PCPreparedVerifierKey<VerifierKey<E>> for PreparedVerifierKey<E> { + /// prepare `PreparedVerifierKey` from `VerifierKey` + fn prepare(vk: &VerifierKey<E>) -> Self { + let prepared_vk = kzg10::PreparedVerifierKey::<E>::prepare(&vk.vk); + + let supported_bits = E::Fr::size_in_bits(); + + let prepared_degree_bounds_and_shift_powers: Option<Vec<(usize, Vec<E::G1Affine>)>> = + if vk.degree_bounds_and_shift_powers.is_some() { + let mut res = Vec::<(usize, Vec<E::G1Affine>)>::new(); + + let degree_bounds_and_shift_powers = + vk.degree_bounds_and_shift_powers.as_ref().unwrap(); + + for (d, shift_power) in degree_bounds_and_shift_powers { + let mut prepared_shift_power = Vec::<E::G1Affine>::new(); + + let mut cur = E::G1Projective::from(shift_power.clone()); + for _ in 0..supported_bits { + prepared_shift_power.push(cur.clone().into()); + cur.double_in_place(); + } + + res.push((d.clone(), prepared_shift_power)); + } + + Some(res) + } else { + None + }; + + Self { + prepared_vk, + prepared_degree_bounds_and_shift_powers, + max_degree: vk.max_degree, + supported_degree: vk.supported_degree, + } + } +} + /// Commitment to a polynomial that optionally enforces a degree bound. #[derive(Derivative)] #[derivative( @@ -195,6 +256,34 @@ impl<E: PairingEngine> PCCommitment for Commitment<E> { } } +/// Prepared commitment to a polynomial that optionally enforces a degree bound. +#[derive(Derivative)] +#[derivative( + Hash(bound = ""), + Clone(bound = ""), + Debug(bound = ""), + PartialEq(bound = ""), + Eq(bound = "") +)] +pub struct PreparedCommitment<E: PairingEngine> { + pub(crate) prepared_comm: kzg10::PreparedCommitment<E>, + pub(crate) shifted_comm: Option<kzg10::Commitment<E>>, +} + +impl<E: PairingEngine> PCPreparedCommitment<Commitment<E>> for PreparedCommitment<E> { + /// Prepare commitment to a polynomial that optionally enforces a degree bound. + fn prepare(comm: &Commitment<E>) -> Self { + let prepared_comm = kzg10::PreparedCommitment::<E>::prepare(&comm.comm); + + let shifted_comm = comm.shifted_comm.clone(); + + Self { + prepared_comm, + shifted_comm, + } + } +} + /// `Randomness` hides the polynomial inside a commitment. It is output by `KZG10::commit`. #[derive(Derivative)] #[derivative( diff --git a/src/marlin_pc/mod.rs b/src/marlin_pc/mod.rs index 753ba7c..301acea 100644 --- a/src/marlin_pc/mod.rs +++ b/src/marlin_pc/mod.rs @@ -5,7 +5,7 @@ use crate::{LabeledCommitment, LabeledPolynomial, LinearCombination}; use crate::{PCRandomness, PCUniversalParams, Polynomial, PolynomialCommitment}; use ark_ec::{AffineCurve, PairingEngine, ProjectiveCurve}; -use ark_ff::{Field, One, Zero}; +use ark_ff::{One, Zero}; use ark_std::vec; use core::{convert::TryInto, marker::PhantomData}; use rand_core::RngCore; @@ -109,26 +109,31 @@ impl<E: PairingEngine> MarlinKZG10<E> { } /// Accumulate `commitments` and `values` according to `opening_challenge`. - fn accumulate_commitments_and_values<'a>( + fn accumulate_commitments_and_values_individual_opening_challenges<'a>( vk: &VerifierKey<E>, commitments: impl IntoIterator<Item = &'a LabeledCommitment<Commitment<E>>>, values: impl IntoIterator<Item = E::Fr>, - opening_challenge: E::Fr, + opening_challenges: &dyn Fn(u64) -> E::Fr, ) -> 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 challenge_i = E::Fr::one(); + 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; + combined_comm += &commitment.comm.0.mul(challenge_i); combined_value += &(value * &challenge_i); if let Some(degree_bound) = degree_bound { - let challenge_i_1 = challenge_i * &opening_challenge; + let challenge_i_1 = opening_challenges(opening_challenge_counter); + opening_challenge_counter += 1; + let shifted_comm = commitment .shifted_comm .as_ref() @@ -139,11 +144,12 @@ impl<E: PairingEngine> MarlinKZG10<E> { let shift_power = vk .get_shift_power(degree_bound) .ok_or(Error::UnsupportedDegreeBound(degree_bound))?; - let mut adjusted_comm = shifted_comm - &shift_power.mul(value); + + let mut adjusted_comm = shifted_comm - &shift_power.mul(value.clone()); + adjusted_comm *= challenge_i_1; combined_comm += &adjusted_comm; } - challenge_i *= &opening_challenge.square(); } end_timer!(acc_time); @@ -155,7 +161,9 @@ impl<E: PairingEngine> PolynomialCommitment<E::Fr> for MarlinKZG10<E> { type UniversalParams = UniversalParams<E>; type CommitterKey = CommitterKey<E>; type VerifierKey = VerifierKey<E>; + type PreparedVerifierKey = PreparedVerifierKey<E>; type Commitment = Commitment<E>; + type PreparedCommitment = PreparedCommitment<E>; type Randomness = Randomness<E>; type Proof = kzg10::Proof<E>; type BatchProof = Vec<Self::Proof>; @@ -192,14 +200,15 @@ impl<E: PairingEngine> PolynomialCommitment<E::Fr> for MarlinKZG10<E> { let powers_of_gamma_g = (0..=supported_hiding_bound + 1) .map(|i| pp.powers_of_gamma_g[&i]) .collect::<Vec<_>>(); + end_timer!(ck_time); // Construct the core KZG10 verifier key. let vk = kzg10::VerifierKey { - g: pp.powers_of_g[0], + g: pp.powers_of_g[0].clone(), gamma_g: pp.powers_of_gamma_g[&0], - h: pp.h, - beta_h: pp.beta_h, + h: pp.h.clone(), + beta_h: pp.beta_h.clone(), prepared_h: pp.prepared_h.clone(), prepared_beta_h: pp.prepared_beta_h.clone(), }; @@ -217,8 +226,11 @@ impl<E: PairingEngine> PolynomialCommitment<E::Fr> for MarlinKZG10<E> { if enforced_degree_bounds.is_empty() { (None, None) } else { + let mut sorted_enforced_degree_bounds = enforced_degree_bounds.clone(); + sorted_enforced_degree_bounds.sort(); + let lowest_shifted_power = max_degree - - enforced_degree_bounds + - sorted_enforced_degree_bounds .last() .ok_or(Error::EmptyDegreeBounds)?; @@ -232,7 +244,7 @@ impl<E: PairingEngine> PolynomialCommitment<E::Fr> for MarlinKZG10<E> { let degree_bounds_and_shift_powers = enforced_degree_bounds .iter() - .map(|d| (*d, pp.powers_of_g[max_degree - d])) + .map(|d| (*d, pp.powers_of_g[max_degree - *d])) .collect(); (Some(shifted_powers), Some(degree_bounds_and_shift_powers)) } @@ -260,7 +272,7 @@ impl<E: PairingEngine> PolynomialCommitment<E::Fr> for MarlinKZG10<E> { /// Outputs a commitment to `polynomial`. fn commit<'a>( ck: &Self::CommitterKey, - polynomials: impl IntoIterator<Item = &'a LabeledPolynomial<'a, E::Fr>>, + polynomials: impl IntoIterator<Item = &'a LabeledPolynomial<E::Fr>>, rng: Option<&mut dyn RngCore>, ) -> Result< ( @@ -328,18 +340,18 @@ impl<E: PairingEngine> PolynomialCommitment<E::Fr> for MarlinKZG10<E> { } /// On input a polynomial `p` and a point `point`, outputs a proof for the same. - fn open<'a>( - ck: &Self::CommitterKey, - labeled_polynomials: impl IntoIterator<Item = &'a LabeledPolynomial<'a, E::Fr>>, - _commitments: impl IntoIterator<Item = &'a LabeledCommitment<Self::Commitment>>, + fn open_individual_opening_challenges<'a>( + ck: &CommitterKey<E>, + labeled_polynomials: impl IntoIterator<Item = &'a LabeledPolynomial<E::Fr>>, + _commitments: impl IntoIterator<Item = &'a LabeledCommitment<Commitment<E>>>, point: E::Fr, - opening_challenge: E::Fr, - rands: impl IntoIterator<Item = &'a Self::Randomness>, + opening_challenges: &dyn Fn(u64) -> E::Fr, + rands: impl IntoIterator<Item = &'a Randomness<E>>, _rng: Option<&mut dyn RngCore>, - ) -> Result<Self::Proof, Self::Error> + ) -> Result<kzg10::Proof<E>, Error> where - Self::Randomness: 'a, - Self::Commitment: 'a, + Randomness<E>: 'a, + Commitment<E>: 'a, { let mut p = Polynomial::zero(); let mut r = kzg10::Randomness::empty(); @@ -348,7 +360,8 @@ impl<E: PairingEngine> PolynomialCommitment<E::Fr> for MarlinKZG10<E> { let mut shifted_r_witness = Polynomial::zero(); let mut enforce_degree_bound = false; - for (j, (polynomial, rand)) in labeled_polynomials.into_iter().zip(rands).enumerate() { + let mut opening_challenge_counter = 0; + for (polynomial, rand) in labeled_polynomials.into_iter().zip(rands) { let degree_bound = polynomial.degree_bound(); let enforced_degree_bounds: Option<&[usize]> = ck @@ -363,7 +376,8 @@ impl<E: PairingEngine> PolynomialCommitment<E::Fr> for MarlinKZG10<E> { )?; // compute challenge^j and challenge^{j+1}. - let challenge_j = opening_challenge.pow([2 * j as u64]); + let challenge_j = opening_challenges(opening_challenge_counter); + opening_challenge_counter += 1; assert_eq!(degree_bound.is_some(), rand.shifted_rand.is_some()); @@ -378,7 +392,8 @@ impl<E: PairingEngine> PolynomialCommitment<E::Fr> for MarlinKZG10<E> { point, &shifted_rand, )?; - let challenge_j_1 = challenge_j * &opening_challenge; + let challenge_j_1 = opening_challenges(opening_challenge_counter); + opening_challenge_counter += 1; let shifted_witness = shift_polynomial(ck, &witness, degree_bound); @@ -420,52 +435,59 @@ impl<E: PairingEngine> PolynomialCommitment<E::Fr> for MarlinKZG10<E> { /// Verifies that `value` is the evaluation at `x` of the polynomial /// committed inside `comm`. - fn check<'a>( - vk: &Self::VerifierKey, - commitments: impl IntoIterator<Item = &'a LabeledCommitment<Self::Commitment>>, + fn check_individual_opening_challenges<'a>( + vk: &VerifierKey<E>, + commitments: impl IntoIterator<Item = &'a LabeledCommitment<Commitment<E>>>, point: E::Fr, values: impl IntoIterator<Item = E::Fr>, - proof: &Self::Proof, - opening_challenge: E::Fr, + proof: &kzg10::Proof<E>, + opening_challenges: &dyn Fn(u64) -> E::Fr, _rng: Option<&mut dyn RngCore>, - ) -> Result<bool, Self::Error> + ) -> Result<bool, Error> where - Self::Commitment: 'a, + Commitment<E>: 'a, { let check_time = start_timer!(|| "Checking evaluations"); let (combined_comm, combined_value) = - Self::accumulate_commitments_and_values(vk, commitments, values, opening_challenge)?; + Self::accumulate_commitments_and_values_individual_opening_challenges( + vk, + commitments, + values, + opening_challenges, + )?; let combined_comm = kzg10::Commitment(combined_comm.into()); let result = kzg10::KZG10::check(&vk.vk, &combined_comm, point, combined_value, proof)?; end_timer!(check_time); Ok(result) } - fn batch_check<'a, R: RngCore>( - vk: &Self::VerifierKey, - commitments: impl IntoIterator<Item = &'a LabeledCommitment<Self::Commitment>>, + fn batch_check_individual_opening_challenges<'a, R: RngCore>( + vk: &VerifierKey<E>, + commitments: impl IntoIterator<Item = &'a LabeledCommitment<Commitment<E>>>, query_set: &QuerySet<E::Fr>, - values: &Evaluations<E::Fr>, - proof: &Self::BatchProof, - opening_challenge: E::Fr, + evaluations: &Evaluations<E::Fr>, + proof: &Vec<kzg10::Proof<E>>, + opening_challenges: &dyn Fn(u64) -> E::Fr, rng: &mut R, - ) -> Result<bool, Self::Error> + ) -> Result<bool, Error> where - Self::Commitment: 'a, + Commitment<E>: 'a, { let commitments: BTreeMap<_, _> = commitments.into_iter().map(|c| (c.label(), c)).collect(); let mut query_to_labels_map = BTreeMap::new(); - for (label, point) in query_set.iter() { - let labels = query_to_labels_map.entry(point).or_insert(BTreeSet::new()); - labels.insert(label); + for (label, (point_label, point)) in query_set.iter() { + let labels = query_to_labels_map + .entry(point_label) + .or_insert((point, BTreeSet::new())); + labels.1.insert(label); } assert_eq!(proof.len(), query_to_labels_map.len()); let mut combined_comms = Vec::new(); let mut combined_queries = Vec::new(); let mut combined_evals = Vec::new(); - for (query, labels) in query_to_labels_map.into_iter() { + for (_, (point, labels)) in query_to_labels_map.into_iter() { let lc_time = start_timer!(|| format!("Randomly combining {} commitments", labels.len())); let mut comms_to_combine: Vec<&'_ LabeledCommitment<_>> = Vec::new(); @@ -480,24 +502,27 @@ impl<E: PairingEngine> PolynomialCommitment<E::Fr> for MarlinKZG10<E> { commitment.commitment().shifted_comm.is_some() ); - let v_i = values - .get(&(label.clone(), *query)) - .ok_or(Error::MissingEvaluation { - label: label.to_string(), - })?; + let v_i = + evaluations + .get(&(label.clone(), *point)) + .ok_or(Error::MissingEvaluation { + label: label.to_string(), + })?; comms_to_combine.push(commitment); values_to_combine.push(*v_i); } - let (c, v) = Self::accumulate_commitments_and_values( + + let (c, v) = Self::accumulate_commitments_and_values_individual_opening_challenges( vk, comms_to_combine, values_to_combine, - opening_challenge, + opening_challenges, )?; end_timer!(lc_time); + combined_comms.push(c); - combined_queries.push(*query); + combined_queries.push(*point); combined_evals.push(v); } let norm_time = start_timer!(|| "Normalizaing combined commitments"); @@ -520,19 +545,19 @@ impl<E: PairingEngine> PolynomialCommitment<E::Fr> for MarlinKZG10<E> { Ok(result) } - fn open_combinations<'a>( - ck: &Self::CommitterKey, + fn open_combinations_individual_opening_challenges<'a>( + ck: &CommitterKey<E>, lc_s: impl IntoIterator<Item = &'a LinearCombination<E::Fr>>, - polynomials: impl IntoIterator<Item = &'a LabeledPolynomial<'a, E::Fr>>, - commitments: impl IntoIterator<Item = &'a LabeledCommitment<Self::Commitment>>, + polynomials: impl IntoIterator<Item = &'a LabeledPolynomial<E::Fr>>, + commitments: impl IntoIterator<Item = &'a LabeledCommitment<Commitment<E>>>, query_set: &QuerySet<E::Fr>, - opening_challenge: E::Fr, - rands: impl IntoIterator<Item = &'a Self::Randomness>, + opening_challenges: &dyn Fn(u64) -> E::Fr, + rands: impl IntoIterator<Item = &'a Randomness<E>>, rng: Option<&mut dyn RngCore>, - ) -> Result<BatchLCProof<E::Fr, Self>, Self::Error> + ) -> Result<BatchLCProof<E::Fr, Self>, Error> where - Self::Randomness: 'a, - Self::Commitment: 'a, + Randomness<E>: 'a, + Commitment<E>: 'a, { let label_map = polynomials .into_iter() @@ -552,7 +577,7 @@ impl<E: PairingEngine> PolynomialCommitment<E::Fr> for MarlinKZG10<E> { let mut degree_bound = None; let mut hiding_bound = None; - let mut randomness = Self::Randomness::empty(); + let mut randomness = Randomness::<E>::empty(); assert!(randomness.shifted_rand.is_none()); let mut coeffs_and_comms = Vec::new(); @@ -573,7 +598,7 @@ impl<E: PairingEngine> PolynomialCommitment<E::Fr> for MarlinKZG10<E> { degree_bound = cur_poly.degree_bound(); } else if cur_poly.degree_bound().is_some() { eprintln!("Degree bound when number of equations is non-zero"); - return Err(Self::Error::EquationHasDegreeBounds(lc_label)); + return Err(Error::EquationHasDegreeBounds(lc_label)); } // Some(_) > None, always. @@ -588,7 +613,7 @@ impl<E: PairingEngine> PolynomialCommitment<E::Fr> for MarlinKZG10<E> { } let lc_poly = - LabeledPolynomial::new_owned(lc_label.clone(), poly, degree_bound, hiding_bound); + LabeledPolynomial::new(lc_label.clone(), poly, degree_bound, hiding_bound); lc_polynomials.push(lc_poly); lc_randomness.push(randomness); lc_commitments.push(Self::combine_commitments(coeffs_and_comms)); @@ -602,12 +627,12 @@ impl<E: PairingEngine> PolynomialCommitment<E::Fr> for MarlinKZG10<E> { .map(|((label, d), c)| LabeledCommitment::new(label, c, d)) .collect::<Vec<_>>(); - let proof = Self::batch_open( + let proof = Self::batch_open_individual_opening_challenges( ck, lc_polynomials.iter(), lc_commitments.iter(), &query_set, - opening_challenge, + opening_challenges, lc_randomness.iter(), rng, )?; @@ -617,18 +642,18 @@ impl<E: PairingEngine> PolynomialCommitment<E::Fr> for MarlinKZG10<E> { /// Checks that `values` are the true evaluations at `query_set` of the polynomials /// committed in `labeled_commitments`. - fn check_combinations<'a, R: RngCore>( - vk: &Self::VerifierKey, + fn check_combinations_individual_opening_challenges<'a, R: RngCore>( + vk: &VerifierKey<E>, lc_s: impl IntoIterator<Item = &'a LinearCombination<E::Fr>>, - commitments: impl IntoIterator<Item = &'a LabeledCommitment<Self::Commitment>>, + commitments: impl IntoIterator<Item = &'a LabeledCommitment<Commitment<E>>>, query_set: &QuerySet<E::Fr>, evaluations: &Evaluations<E::Fr>, proof: &BatchLCProof<E::Fr, Self>, - opening_challenge: E::Fr, + opening_challenges: &dyn Fn(u64) -> E::Fr, rng: &mut R, - ) -> Result<bool, Self::Error> + ) -> Result<bool, Error> where - Self::Commitment: 'a, + Commitment<E>: 'a, { let BatchLCProof { proof, .. } = proof; let label_comm_map = commitments @@ -668,9 +693,9 @@ impl<E: PairingEngine> PolynomialCommitment<E::Fr> for MarlinKZG10<E> { ); degree_bound = cur_comm.degree_bound(); } else if cur_comm.degree_bound().is_some() { - return Err(Self::Error::EquationHasDegreeBounds(lc_label)); + return Err(Error::EquationHasDegreeBounds(lc_label)); } - coeffs_and_comms.push((*coeff, cur_comm.commitment())); + coeffs_and_comms.push((coeff.clone(), cur_comm.commitment())); } } let lc_time = @@ -689,16 +714,91 @@ impl<E: PairingEngine> PolynomialCommitment<E::Fr> for MarlinKZG10<E> { .collect::<Vec<_>>(); end_timer!(combined_comms_norm_time); - Self::batch_check( + Self::batch_check_individual_opening_challenges( vk, &lc_commitments, &query_set, &evaluations, proof, - opening_challenge, + opening_challenges, 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_individual_opening_challenges<'a>( + ck: &CommitterKey<E>, + labeled_polynomials: impl IntoIterator<Item = &'a LabeledPolynomial<E::Fr>>, + commitments: impl IntoIterator<Item = &'a LabeledCommitment<Commitment<E>>>, + query_set: &QuerySet<E::Fr>, + opening_challenges: &dyn Fn(u64) -> E::Fr, + rands: impl IntoIterator<Item = &'a Randomness<E>>, + rng: Option<&mut dyn RngCore>, + ) -> Result<Vec<kzg10::Proof<E>>, Error> + where + Randomness<E>: 'a, + Commitment<E>: 'a, + { + let rng = &mut crate::optional_rng::OptionalRng(rng); + let poly_rand_comm: BTreeMap<_, _> = labeled_polynomials + .into_iter() + .zip(rands) + .zip(commitments.into_iter()) + .map(|((poly, r), comm)| (poly.label(), (poly, r, comm))) + .collect(); + + let open_time = start_timer!(|| format!( + "Opening {} polynomials at query set of size {}", + poly_rand_comm.len(), + query_set.len(), + )); + + let mut query_to_labels_map = BTreeMap::new(); + + for (label, (point_label, point)) in query_set.iter() { + let labels = query_to_labels_map + .entry(point_label) + .or_insert((point, BTreeSet::new())); + labels.1.insert(label); + } + + let mut proofs = Vec::new(); + for (_point_label, (point, labels)) in query_to_labels_map.into_iter() { + let mut query_polys: Vec<&'a LabeledPolynomial<_>> = Vec::new(); + let mut query_rands: Vec<&'a Randomness<E>> = Vec::new(); + let mut query_comms: Vec<&'a LabeledCommitment<Commitment<E>>> = Vec::new(); + + for label in labels { + let (polynomial, rand, comm) = + poly_rand_comm.get(&label).ok_or(Error::MissingPolynomial { + label: label.to_string(), + })?; + + query_polys.push(polynomial); + query_rands.push(rand); + query_comms.push(comm); + } + + let proof_time = start_timer!(|| "Creating proof"); + let proof = Self::open_individual_opening_challenges( + ck, + query_polys, + query_comms, + point.clone(), + opening_challenges, + query_rands, + Some(rng), + )?; + + end_timer!(proof_time); + + proofs.push(proof); + } + end_timer!(open_time); + + Ok(proofs.into()) + } } #[cfg(test)] diff --git a/src/sonic_pc/data_structures.rs b/src/sonic_pc/data_structures.rs index 6b5f3a4..41dacd2 100644 --- a/src/sonic_pc/data_structures.rs +++ b/src/sonic_pc/data_structures.rs @@ -1,6 +1,8 @@ use crate::kzg10; -use crate::{BTreeMap, PCCommitterKey, PCVerifierKey, Vec}; -use ark_ec::PairingEngine; +use crate::{ + BTreeMap, PCCommitterKey, PCPreparedCommitment, PCPreparedVerifierKey, PCVerifierKey, Vec, +}; +use ark_ec::{PairingEngine, ProjectiveCurve}; /// `UniversalParams` are the universal parameters for the KZG10 scheme. pub type UniversalParams<E> = kzg10::UniversalParams<E>; @@ -11,6 +13,23 @@ pub type Randomness<E> = kzg10::Randomness<E>; /// `Commitment` is the commitment for the KZG10 scheme. pub type Commitment<E> = kzg10::Commitment<E>; +/// `PreparedCommitment` is the prepared commitment for the KZG10 scheme. +pub type PreparedCommitment<E> = kzg10::PreparedCommitment<E>; + +impl<E: PairingEngine> PCPreparedCommitment<Commitment<E>> for PreparedCommitment<E> { + /// prepare `PreparedCommitment` from `Commitment` + fn prepare(comm: &Commitment<E>) -> Self { + let mut prepared_comm = Vec::<E::G1Affine>::new(); + let mut cur = E::G1Projective::from(comm.0.clone()); + for _ in 0..128 { + prepared_comm.push(cur.clone().into()); + cur.double_in_place(); + } + + Self { 0: prepared_comm } + } +} + /// `ComitterKey` is used to commit to, and create evaluation proofs for, a given /// polynomial. #[derive(Derivative)] @@ -158,6 +177,16 @@ impl<E: PairingEngine> PCVerifierKey for VerifierKey<E> { } } +/// Nothing to do to prepare this verifier key (for now). +pub type PreparedVerifierKey<E> = VerifierKey<E>; + +impl<E: PairingEngine> PCPreparedVerifierKey<VerifierKey<E>> for PreparedVerifierKey<E> { + /// prepare `PreparedVerifierKey` from `VerifierKey` + fn prepare(vk: &VerifierKey<E>) -> Self { + vk.clone() + } +} + /// Evaluation proof at a query set. #[derive(Derivative)] #[derivative( diff --git a/src/sonic_pc/mod.rs b/src/sonic_pc/mod.rs index ed6b5b1..4cd9030 100644 --- a/src/sonic_pc/mod.rs +++ b/src/sonic_pc/mod.rs @@ -28,7 +28,7 @@ pub struct SonicKZG10<E: PairingEngine> { } impl<E: PairingEngine> SonicKZG10<E> { - fn accumulate_elems<'a>( + fn accumulate_elems_individual_opening_challenges<'a>( combined_comms: &mut BTreeMap<Option<usize>, E::G1Projective>, combined_witness: &mut E::G1Projective, combined_adjusted_witness: &mut E::G1Projective, @@ -37,11 +37,14 @@ impl<E: PairingEngine> SonicKZG10<E> { point: E::Fr, values: impl IntoIterator<Item = E::Fr>, proof: &kzg10::Proof<E>, - opening_challenge: E::Fr, + opening_challenges: &dyn Fn(u64) -> E::Fr, randomizer: Option<E::Fr>, ) { let acc_time = start_timer!(|| "Accumulating elements"); - let mut curr_challenge = opening_challenge; + + let mut opening_challenge_counter = 0; + let mut curr_challenge = opening_challenges(opening_challenge_counter); + opening_challenge_counter += 1; // Keeps track of running combination of values let mut combined_values = E::Fr::zero(); @@ -64,7 +67,8 @@ impl<E: PairingEngine> SonicKZG10<E> { *combined_comms .entry(degree_bound) .or_insert(E::G1Projective::zero()) += &comm_with_challenge; - curr_challenge *= &opening_challenge; + curr_challenge = opening_challenges(opening_challenge_counter); + opening_challenge_counter += 1; } // Push expected results into list of elems. Power will be the negative of the expected power @@ -129,7 +133,9 @@ impl<E: PairingEngine> PolynomialCommitment<E::Fr> for SonicKZG10<E> { type UniversalParams = UniversalParams<E>; type CommitterKey = CommitterKey<E>; type VerifierKey = VerifierKey<E>; + type PreparedVerifierKey = PreparedVerifierKey<E>; type Commitment = Commitment<E>; + type PreparedCommitment = PreparedCommitment<E>; type Randomness = Randomness<E>; type Proof = kzg10::Proof<E>; type BatchProof = Vec<Self::Proof>; @@ -266,7 +272,7 @@ impl<E: PairingEngine> PolynomialCommitment<E::Fr> for SonicKZG10<E> { /// Outputs a commitment to `polynomial`. fn commit<'a>( ck: &Self::CommitterKey, - polynomials: impl IntoIterator<Item = &'a LabeledPolynomial<'a, E::Fr>>, + polynomials: impl IntoIterator<Item = &'a LabeledPolynomial<E::Fr>>, rng: Option<&mut dyn RngCore>, ) -> Result< ( @@ -327,12 +333,12 @@ impl<E: PairingEngine> PolynomialCommitment<E::Fr> for SonicKZG10<E> { Ok((labeled_comms, randomness)) } - fn open<'a>( + fn open_individual_opening_challenges<'a>( ck: &Self::CommitterKey, - labeled_polynomials: impl IntoIterator<Item = &'a LabeledPolynomial<'a, E::Fr>>, + labeled_polynomials: impl IntoIterator<Item = &'a LabeledPolynomial<E::Fr>>, _commitments: impl IntoIterator<Item = &'a LabeledCommitment<Self::Commitment>>, point: E::Fr, - opening_challenge: E::Fr, + opening_challenges: &dyn Fn(u64) -> E::Fr, rands: impl IntoIterator<Item = &'a Self::Randomness>, _rng: Option<&mut dyn RngCore>, ) -> Result<Self::Proof, Self::Error> @@ -342,7 +348,11 @@ impl<E: PairingEngine> PolynomialCommitment<E::Fr> for SonicKZG10<E> { { let mut combined_polynomial = Polynomial::zero(); let mut combined_rand = kzg10::Randomness::empty(); - let mut curr_challenge = opening_challenge; + + let mut opening_challenge_counter = 0; + + let mut curr_challenge = opening_challenges(opening_challenge_counter); + opening_challenge_counter += 1; for (polynomial, rand) in labeled_polynomials.into_iter().zip(rands) { let enforced_degree_bounds: Option<&[usize]> = ck @@ -359,7 +369,8 @@ impl<E: PairingEngine> PolynomialCommitment<E::Fr> for SonicKZG10<E> { combined_polynomial += (curr_challenge, polynomial.polynomial()); combined_rand += (curr_challenge, rand); - curr_challenge *= &opening_challenge; + curr_challenge = opening_challenges(opening_challenge_counter); + opening_challenge_counter += 1; } let proof_time = start_timer!(|| "Creating proof for polynomials"); @@ -369,13 +380,13 @@ impl<E: PairingEngine> PolynomialCommitment<E::Fr> for SonicKZG10<E> { Ok(proof) } - fn check<'a>( + fn check_individual_opening_challenges<'a>( vk: &Self::VerifierKey, commitments: impl IntoIterator<Item = &'a LabeledCommitment<Self::Commitment>>, point: E::Fr, values: impl IntoIterator<Item = E::Fr>, proof: &Self::Proof, - opening_challenge: E::Fr, + opening_challenges: &dyn Fn(u64) -> E::Fr, _rng: Option<&mut dyn RngCore>, ) -> Result<bool, Self::Error> where @@ -386,7 +397,7 @@ impl<E: PairingEngine> PolynomialCommitment<E::Fr> for SonicKZG10<E> { let mut combined_witness: E::G1Projective = E::G1Projective::zero(); let mut combined_adjusted_witness: E::G1Projective = E::G1Projective::zero(); - Self::accumulate_elems( + Self::accumulate_elems_individual_opening_challenges( &mut combined_comms, &mut combined_witness, &mut combined_adjusted_witness, @@ -395,7 +406,7 @@ impl<E: PairingEngine> PolynomialCommitment<E::Fr> for SonicKZG10<E> { point, values, proof, - opening_challenge, + opening_challenges, None, ); @@ -409,13 +420,13 @@ impl<E: PairingEngine> PolynomialCommitment<E::Fr> for SonicKZG10<E> { res } - fn batch_check<'a, R: RngCore>( + fn batch_check_individual_opening_challenges<'a, R: RngCore>( vk: &Self::VerifierKey, commitments: impl IntoIterator<Item = &'a LabeledCommitment<Self::Commitment>>, query_set: &QuerySet<E::Fr>, values: &Evaluations<E::Fr>, proof: &Self::BatchProof, - opening_challenge: E::Fr, + opening_challenges: &dyn Fn(u64) -> E::Fr, rng: &mut R, ) -> Result<bool, Self::Error> where @@ -424,9 +435,11 @@ impl<E: PairingEngine> PolynomialCommitment<E::Fr> for SonicKZG10<E> { let commitments: BTreeMap<_, _> = commitments.into_iter().map(|c| (c.label(), c)).collect(); let mut query_to_labels_map = BTreeMap::new(); - for (label, point) in query_set.iter() { - let labels = query_to_labels_map.entry(point).or_insert(BTreeSet::new()); - labels.insert(label); + for (label, (point_label, point)) in query_set.iter() { + let labels = query_to_labels_map + .entry(point_label) + .or_insert((point, BTreeSet::new())); + labels.1.insert(label); } assert_eq!(proof.len(), query_to_labels_map.len()); @@ -437,7 +450,7 @@ impl<E: PairingEngine> PolynomialCommitment<E::Fr> for SonicKZG10<E> { let mut combined_witness: E::G1Projective = E::G1Projective::zero(); let mut combined_adjusted_witness: E::G1Projective = E::G1Projective::zero(); - for ((query, labels), p) in query_to_labels_map.into_iter().zip(proof) { + for ((_point_label, (point, labels)), p) in query_to_labels_map.into_iter().zip(proof) { let mut comms_to_combine: Vec<&'_ LabeledCommitment<_>> = Vec::new(); let mut values_to_combine = Vec::new(); for label in labels.into_iter() { @@ -446,7 +459,7 @@ impl<E: PairingEngine> PolynomialCommitment<E::Fr> for SonicKZG10<E> { })?; let v_i = values - .get(&(label.clone(), *query)) + .get(&(label.clone(), *point)) .ok_or(Error::MissingEvaluation { label: label.to_string(), })?; @@ -455,16 +468,16 @@ impl<E: PairingEngine> PolynomialCommitment<E::Fr> for SonicKZG10<E> { values_to_combine.push(*v_i); } - Self::accumulate_elems( + Self::accumulate_elems_individual_opening_challenges( &mut combined_comms, &mut combined_witness, &mut combined_adjusted_witness, vk, comms_to_combine.into_iter(), - *query, + *point, values_to_combine.into_iter(), p, - opening_challenge, + opening_challenges, Some(randomizer), ); @@ -479,13 +492,13 @@ impl<E: PairingEngine> PolynomialCommitment<E::Fr> for SonicKZG10<E> { ) } - fn open_combinations<'a>( + fn open_combinations_individual_opening_challenges<'a>( ck: &Self::CommitterKey, lc_s: impl IntoIterator<Item = &'a LinearCombination<E::Fr>>, - polynomials: impl IntoIterator<Item = &'a LabeledPolynomial<'a, E::Fr>>, + polynomials: impl IntoIterator<Item = &'a LabeledPolynomial<E::Fr>>, commitments: impl IntoIterator<Item = &'a LabeledCommitment<Self::Commitment>>, query_set: &QuerySet<E::Fr>, - opening_challenge: E::Fr, + opening_challenges: &dyn Fn(u64) -> E::Fr, rands: impl IntoIterator<Item = &'a Self::Randomness>, rng: Option<&mut dyn RngCore>, ) -> Result<BatchLCProof<E::Fr, Self>, Self::Error> @@ -540,7 +553,7 @@ impl<E: PairingEngine> PolynomialCommitment<E::Fr> for SonicKZG10<E> { } let lc_poly = - LabeledPolynomial::new_owned(lc_label.clone(), poly, degree_bound, hiding_bound); + LabeledPolynomial::new(lc_label.clone(), poly, degree_bound, hiding_bound); lc_polynomials.push(lc_poly); lc_randomness.push(randomness); lc_commitments.push(comm); @@ -559,12 +572,12 @@ impl<E: PairingEngine> PolynomialCommitment<E::Fr> for SonicKZG10<E> { .map(|((label, d), c)| LabeledCommitment::new(label, c, d)) .collect::<Vec<_>>(); - let proof = Self::batch_open( + let proof = Self::batch_open_individual_opening_challenges( ck, lc_polynomials.iter(), lc_commitments.iter(), &query_set, - opening_challenge, + opening_challenges, lc_randomness.iter(), rng, )?; @@ -573,14 +586,14 @@ impl<E: PairingEngine> PolynomialCommitment<E::Fr> for SonicKZG10<E> { /// Checks that `values` are the true evaluations at `query_set` of the polynomials /// committed in `labeled_commitments`. - fn check_combinations<'a, R: RngCore>( + fn check_combinations_individual_opening_challenges<'a, R: RngCore>( vk: &Self::VerifierKey, lc_s: impl IntoIterator<Item = &'a LinearCombination<E::Fr>>, commitments: impl IntoIterator<Item = &'a LabeledCommitment<Self::Commitment>>, query_set: &QuerySet<E::Fr>, evaluations: &Evaluations<E::Fr>, proof: &BatchLCProof<E::Fr, Self>, - opening_challenge: E::Fr, + opening_challenges: &dyn Fn(u64) -> E::Fr, rng: &mut R, ) -> Result<bool, Self::Error> where @@ -644,13 +657,13 @@ impl<E: PairingEngine> PolynomialCommitment<E::Fr> for SonicKZG10<E> { .map(|((label, d), c)| LabeledCommitment::new(label, c, d)) .collect::<Vec<_>>(); - Self::batch_check( + Self::batch_check_individual_opening_challenges( vk, &lc_commitments, &query_set, &evaluations, proof, - opening_challenge, + opening_challenges, rng, ) } -- GitLab