Add CommitmentProver trait, and add KZG prover to it (#62) * Add KZG commitment scheme adapted to vector commitment Add KZG commitment scheme adapted to vector commitment Also move the `src/pedersen.rs` into `src/commitment/pedersen.rs` where it will coexist with `kzg.rs` and the trait defined in `src/commitment/mod.rs`. * Adapt Pedersen into the new CommitmentProver trait * add CommitmentProver (Pedersen&KZG) homomorphic property test * polishing * Use divide_with_q_and_r, rename skip_first_zero_coeffs Co-authored-by: han0110 <tinghan0110@gmail.com> --------- Co-authored-by: han0110 <tinghan0110@gmail.com>
jump to
@@ -9,6 +9,7 @@ ark-ff = "^0.4.0"
ark-poly = "^0.4.0" ark-std = "^0.4.0" ark-crypto-primitives = { version = "^0.4.0", default-features = false, features = ["r1cs", "sponge", "crh"] } +ark-poly-commit = "^0.4.0" ark-relations = { version = "^0.4.0", default-features = false } ark-r1cs-std = { default-features = false } # use latest version from the patch ark-serialize = "^0.4.0"
@@ -0,0 +1,234 @@
+/// Adaptation of the prover methods and structs from arkworks/poly-commit's KZG10 implementation +/// into the CommitmentProver trait. +/// +/// The motivation to do so, is that we want to be able to use KZG / Pedersen for committing to +/// vectors indistinctly, and the arkworks KZG10 implementation contains all the methods under the +/// same trait, which requires the Pairing trait, where the prover does not need access to the +/// Pairing but only to G1. +/// For our case, we want the folding schemes prover to be agnostic to pairings, since in the +/// non-ethereum cases we may use non-pairing-friendly curves with Pedersen commitments, so the +/// trait & types that we use should not depend on the Pairing type for the prover. Therefore, we +/// separate the CommitmentSchemeProver from the setup and verify phases, so the prover can be +/// defined without depending on pairings. +use ark_ec::{pairing::Pairing, CurveGroup, VariableBaseMSM}; +use ark_ff::PrimeField; +use ark_poly::{ + univariate::{DenseOrSparsePolynomial, DensePolynomial}, + DenseUVPolynomial, EvaluationDomain, Evaluations, GeneralEvaluationDomain, Polynomial, +}; +use ark_poly_commit::kzg10::{VerifierKey, KZG10}; +use ark_std::rand::Rng; +use ark_std::{borrow::Cow, fmt::Debug}; +use ark_std::{One, Zero}; +use core::marker::PhantomData; +use rayon::iter::{IntoParallelRefIterator, ParallelIterator}; + +use super::CommitmentProver; +use crate::transcript::Transcript; +use crate::Error; + +/// ProverKey defines a similar struct as in ark_poly_commit::kzg10::Powers, but instead of +/// depending on the Pairing trait it depends on the CurveGroup trait. +#[derive(Debug, Clone, Default, Eq, PartialEq)] +pub struct ProverKey<'a, C: CurveGroup> { + /// Group elements of the form `β^i G`, for different values of `i`. + pub powers_of_g: Cow<'a, [C::Affine]>, +} + +pub struct KZGSetup<P: Pairing> { + _p: PhantomData<P>, +} +impl<'a, P> KZGSetup<P> +where + P: Pairing, +{ + /// setup returns the tuple (ProverKey, VerifierKey). For real world deployments the setup must + /// be computed in the most trustless way possible, usually through a MPC ceremony. + pub fn setup<R: Rng>(rng: &mut R, len: usize) -> (ProverKey<'a, P::G1>, VerifierKey<P>) { + let len = len.next_power_of_two(); + let universal_params = KZG10::<P, DensePolynomial<P::ScalarField>>::setup(len, false, rng) + .expect("Setup failed"); + let powers_of_g = universal_params.powers_of_g[..=len].to_vec(); + let powers = ProverKey::<P::G1> { + powers_of_g: ark_std::borrow::Cow::Owned(powers_of_g), + }; + let vk = VerifierKey { + g: universal_params.powers_of_g[0], + gamma_g: universal_params.powers_of_gamma_g[&0], + h: universal_params.h, + beta_h: universal_params.beta_h, + prepared_h: universal_params.prepared_h.clone(), + prepared_beta_h: universal_params.prepared_beta_h.clone(), + }; + (powers, vk) + } +} + +/// KZGProver implements the CommitmentProver trait for the KZG commitment scheme. +pub struct KZGProver<'a, C: CurveGroup> { + _a: PhantomData<&'a ()>, + _c: PhantomData<C>, +} +impl<'a, C> CommitmentProver<C> for KZGProver<'a, C> +where + C: CurveGroup, +{ + type Params = ProverKey<'a, C>; + /// Proof is a tuple containing (evaluation, proof) + type Proof = (C::ScalarField, C); + + /// commit implements the CommitmentProver commit interface, adapting the implementation from + /// https://github.com/arkworks-rs/poly-commit/tree/c724fa666e935bbba8db5a1421603bab542e15ab/poly-commit/src/kzg10/mod.rs#L178 + /// with the main difference being the removal of the blinding factors and the no-dependancy to + /// the Pairing trait. + fn commit( + params: &Self::Params, + v: &[C::ScalarField], + _blind: &C::ScalarField, + ) -> Result<C, Error> { + if !_blind.is_zero() { + return Err(Error::NotSupportedYet("blinding factors".to_string())); + } + + let polynomial = poly_from_vec(v.to_vec())?; + check_degree_is_too_large(polynomial.degree(), params.powers_of_g.len())?; + + let (num_leading_zeros, plain_coeffs) = + skip_first_zero_coeffs_and_convert_to_bigints(&polynomial); + let commitment = <C as VariableBaseMSM>::msm_bigint( + ¶ms.powers_of_g[num_leading_zeros..], + &plain_coeffs, + ); + Ok(commitment) + } + + /// prove implements the CommitmentProver prove interface, adapting the implementation from + /// https://github.com/arkworks-rs/poly-commit/tree/c724fa666e935bbba8db5a1421603bab542e15ab/poly-commit/src/kzg10/mod.rs#L307 + /// with the main difference being the removal of the blinding factors and the no-dependancy to + /// the Pairing trait. + fn prove( + params: &Self::Params, + transcript: &mut impl Transcript<C>, + cm: &C, + v: &[C::ScalarField], + _blind: &C::ScalarField, + ) -> Result<Self::Proof, Error> { + if !_blind.is_zero() { + return Err(Error::NotSupportedYet("blinding factors".to_string())); + } + + let polynomial = poly_from_vec(v.to_vec())?; + check_degree_is_too_large(polynomial.degree(), params.powers_of_g.len())?; + + transcript.absorb_point(cm)?; + let challenge = transcript.get_challenge(); + + // Compute q(x) = (p(x) - p(z)) / (x-z). Observe that this quotient does not change with z + // because p(z) is the remainder term. We can therefore omit p(z) when computing the + // quotient. + let divisor = DensePolynomial::<C::ScalarField>::from_coefficients_vec(vec![ + -challenge, + C::ScalarField::one(), + ]); + let (witness_poly, remainder_poly) = DenseOrSparsePolynomial::from(&polynomial) + .divide_with_q_and_r(&DenseOrSparsePolynomial::from(&divisor)) + // the panic inside `divide_with_q_and_r` should never be reached, since the divisor + // polynomial is constructed right before and is set to not be zero. And the `.unwrap` + // should not give an error. + .unwrap(); + let evaluation = remainder_poly[0]; + + check_degree_is_too_large(witness_poly.degree(), params.powers_of_g.len())?; + let (num_leading_zeros, witness_coeffs) = + skip_first_zero_coeffs_and_convert_to_bigints(&witness_poly); + let proof = <C as VariableBaseMSM>::msm_bigint( + ¶ms.powers_of_g[num_leading_zeros..], + &witness_coeffs, + ); + + Ok((evaluation, proof)) + } +} + +/// returns the interpolated polynomial of degree=v.len().next_power_of_two(), which passes through all +/// the given elements of v. +fn poly_from_vec<F: PrimeField>(v: Vec<F>) -> Result<DensePolynomial<F>, Error> { + let D = GeneralEvaluationDomain::<F>::new(v.len()).ok_or(Error::NewDomainFail)?; + Ok(Evaluations::from_vec_and_domain(v, D).interpolate()) +} + +fn check_degree_is_too_large( + degree: usize, + num_powers: usize, +) -> Result<(), ark_poly_commit::error::Error> { + let num_coefficients = degree + 1; + if num_coefficients > num_powers { + Err(ark_poly_commit::error::Error::TooManyCoefficients { + num_coefficients, + num_powers, + }) + } else { + Ok(()) + } +} + +fn skip_first_zero_coeffs_and_convert_to_bigints<F: PrimeField, P: DenseUVPolynomial<F>>( + p: &P, +) -> (usize, Vec<F::BigInt>) { + let mut num_leading_zeros = 0; + while num_leading_zeros < p.coeffs().len() && p.coeffs()[num_leading_zeros].is_zero() { + num_leading_zeros += 1; + } + let coeffs = convert_to_bigints(&p.coeffs()[num_leading_zeros..]); + (num_leading_zeros, coeffs) +} + +fn convert_to_bigints<F: PrimeField>(p: &[F]) -> Vec<F::BigInt> { + ark_std::cfg_iter!(p) + .map(|s| s.into_bigint()) + .collect::<Vec<_>>() +} + +#[cfg(test)] +mod tests { + use ark_bn254::{Bn254, Fr, G1Projective as G1}; + use ark_poly_commit::kzg10::{Commitment as KZG10Commitment, Proof as KZG10Proof, KZG10}; + use ark_std::{test_rng, UniformRand}; + + use super::*; + use crate::transcript::poseidon::{tests::poseidon_test_config, PoseidonTranscript}; + + #[test] + fn test_kzg_commitment_scheme() { + let rng = &mut test_rng(); + let poseidon_config = poseidon_test_config::<Fr>(); + let transcript_p = &mut PoseidonTranscript::<G1>::new(&poseidon_config); + let transcript_v = &mut PoseidonTranscript::<G1>::new(&poseidon_config); + + let n = 10; + let (pk, vk): (ProverKey<G1>, VerifierKey<Bn254>) = KZGSetup::<Bn254>::setup(rng, n); + + let v: Vec<Fr> = std::iter::repeat_with(|| Fr::rand(rng)).take(n).collect(); + let cm = KZGProver::<G1>::commit(&pk, &v, &Fr::zero()).unwrap(); + + let (eval, proof) = + KZGProver::<G1>::prove(&pk, transcript_p, &cm, &v, &Fr::zero()).unwrap(); + + // verify the proof: + // get evaluation challenge + transcript_v.absorb_point(&cm).unwrap(); + let challenge = transcript_v.get_challenge(); + // verify the KZG proof using arkworks method + assert!(KZG10::<Bn254, DensePolynomial<Fr>>::check( + &vk, + &KZG10Commitment(cm.into_affine()), + challenge, + eval, + &KZG10Proof::<Bn254> { + w: proof.into_affine(), + random_v: None, + }, + ) + .unwrap()); + } +}
@@ -0,0 +1,127 @@
+use ark_ec::CurveGroup; +use ark_std::fmt::Debug; + +use crate::transcript::Transcript; +use crate::Error; + +pub mod kzg; +pub mod pedersen; + +/// CommitmentProver defines the vector commitment scheme prover trait. +pub trait CommitmentProver<C: CurveGroup> { + type Params: Debug; + type Proof: Debug; + + fn commit( + params: &Self::Params, + v: &[C::ScalarField], + blind: &C::ScalarField, + ) -> Result<C, Error>; + fn prove( + params: &Self::Params, + transcript: &mut impl Transcript<C>, + cm: &C, + v: &[C::ScalarField], + blind: &C::ScalarField, + ) -> Result<Self::Proof, Error>; +} + +#[cfg(test)] +mod tests { + use super::*; + use ark_bn254::{Bn254, Fr, G1Projective as G1}; + use ark_crypto_primitives::sponge::{poseidon::PoseidonConfig, Absorb}; + use ark_poly::univariate::DensePolynomial; + use ark_poly_commit::kzg10::{ + Commitment as KZG10Commitment, Proof as KZG10Proof, VerifierKey, KZG10, + }; + use ark_std::Zero; + use ark_std::{test_rng, UniformRand}; + + use super::kzg::{KZGProver, KZGSetup, ProverKey}; + use super::pedersen::Pedersen; + use crate::transcript::{ + poseidon::{tests::poseidon_test_config, PoseidonTranscript}, + Transcript, + }; + + // Computes the commitment of the two vectors using the given CommitmentProver, then computes + // their random linear combination, and returns it together with the proof of it. + fn commit_rlc_and_prove<C: CurveGroup, CP: CommitmentProver<C>>( + poseidon_config: &PoseidonConfig<C::ScalarField>, + params: &CP::Params, + r: C::ScalarField, + v_1: &[C::ScalarField], + v_2: &[C::ScalarField], + ) -> Result<(C, CP::Proof), Error> + where + <C as ark_ec::Group>::ScalarField: Absorb, + { + let cm_1 = CP::commit(params, v_1, &C::ScalarField::zero())?; + let cm_2 = CP::commit(params, v_2, &C::ScalarField::zero())?; + + // random linear combination of the commitment and the witness (vector v) + let cm_3 = cm_1 + cm_2.mul(r); + let v_3: Vec<C::ScalarField> = v_1.iter().zip(v_2).map(|(a, b)| *a + (r * b)).collect(); + + let transcript = &mut PoseidonTranscript::<C>::new(poseidon_config); + let proof = CP::prove(params, transcript, &cm_3, &v_3, &C::ScalarField::zero()).unwrap(); + + Ok((cm_3, proof)) + } + + #[test] + fn test_homomorphic_property_using_CommitmentProver_trait() { + let rng = &mut test_rng(); + let poseidon_config = poseidon_test_config::<Fr>(); + let n: usize = 100; + + // set random vector for the test + let v_1: Vec<Fr> = std::iter::repeat_with(|| Fr::rand(rng)).take(n).collect(); + let v_2: Vec<Fr> = std::iter::repeat_with(|| Fr::rand(rng)).take(n).collect(); + // set a random challenge for the random linear combination + let r = Fr::rand(rng); + + // setup params for Pedersen & KZG + let pedersen_params = Pedersen::<G1>::new_params(rng, n); + let (kzg_pk, kzg_vk): (ProverKey<G1>, VerifierKey<Bn254>) = + KZGSetup::<Bn254>::setup(rng, n); + + // Pedersen commit the two vectors and return their random linear combination and proof + let (pedersen_cm, pedersen_proof) = commit_rlc_and_prove::<G1, Pedersen<G1>>( + &poseidon_config, + &pedersen_params, + r, + &v_1, + &v_2, + ) + .unwrap(); + + // KZG commit the two vectors and return their random linear combination and proof + let (kzg_cm, kzg_proof) = + commit_rlc_and_prove::<G1, KZGProver<G1>>(&poseidon_config, &kzg_pk, r, &v_1, &v_2) + .unwrap(); + + // verify Pedersen + let transcript_v = &mut PoseidonTranscript::<G1>::new(&poseidon_config); + Pedersen::<G1>::verify(&pedersen_params, transcript_v, pedersen_cm, pedersen_proof) + .unwrap(); + + // verify KZG + let transcript_v = &mut PoseidonTranscript::<G1>::new(&poseidon_config); + transcript_v.absorb_point(&kzg_cm).unwrap(); + let challenge = transcript_v.get_challenge(); + // verify the KZG proof using arkworks method + assert!(KZG10::<Bn254, DensePolynomial<Fr>>::check( + &kzg_vk, + &KZG10Commitment(kzg_cm.into_affine()), + challenge, + kzg_proof.0, // eval + &KZG10Proof::<Bn254> { + w: kzg_proof.1.into_affine(), // proof + random_v: None, + }, + ) + .unwrap()); + } +}
@@ -9,7 +9,10 @@ use ark_std::{rand::Rng, UniformRand};
use super::utils::compute_sum_Mz; use crate::ccs::CCS; -use crate::pedersen::{Params as PedersenParams, Pedersen}; +use crate::commitment::{ + pedersen::{Params as PedersenParams, Pedersen}, + CommitmentProver, +}; use crate::utils::hypercube::BooleanHypercube; use crate::utils::mle::matrix_to_mle; use crate::utils::mle::vec_to_mle;
@@ -157,11 +157,11 @@ ccs::{
tests::{get_test_ccs, get_test_z}, CCS, }, + commitment::pedersen::Pedersen, folding::hypernova::utils::{ compute_c_from_sigmas_and_thetas, compute_sigmas_and_thetas, sum_ci_mul_prod_thetaj, sum_muls_gamma_pows_eq_sigma, }, - pedersen::Pedersen, utils::virtual_polynomial::eq_eval, }; use ark_pallas::{Fr, Projective};
@@ -8,7 +8,10 @@
use super::cccs::Witness; use super::utils::{compute_all_sum_Mz_evals, compute_sum_Mz}; use crate::ccs::CCS; -use crate::pedersen::{Params as PedersenParams, Pedersen}; +use crate::commitment::{ + pedersen::{Params as PedersenParams, Pedersen}, + CommitmentProver, +}; use crate::utils::mle::{matrix_to_mle, vec_to_mle}; use crate::utils::virtual_polynomial::VirtualPolynomial; use crate::Error;
@@ -213,7 +213,7 @@ // its sum is equal to the extracted_sum from the SumCheck.
////////////////////////////////////////////////////////////////////// let mut g_over_bhc = C::ScalarField::zero(); for x in BooleanHypercube::new(ccs.s) { - g_over_bhc += g.evaluate(&x).unwrap(); + g_over_bhc += g.evaluate(&x)?; } // note: this is the sum of g(x) over the whole boolean hypercube@@ -378,7 +378,7 @@ use crate::transcript::poseidon::PoseidonTranscript;
use ark_std::test_rng; use ark_std::UniformRand; - use crate::pedersen::Pedersen; + use crate::commitment::pedersen::Pedersen; use ark_pallas::{Fr, Projective}; #[test]
@@ -199,7 +199,7 @@ use ark_std::UniformRand;
use ark_std::Zero; use crate::ccs::tests::{get_test_ccs, get_test_z}; - use crate::pedersen::Pedersen; + use crate::commitment::pedersen::Pedersen; use crate::utils::multilinear_polynomial::tests::fix_last_variables; use crate::utils::virtual_polynomial::eq_eval;
@@ -470,12 +470,12 @@ use ark_vesta::{constraints::GVar as GVar2, Projective as Projective2};
use tracing_subscriber::layer::SubscriberExt; use crate::ccs::r1cs::{extract_r1cs, extract_w_x}; + use crate::commitment::pedersen::Pedersen; use crate::folding::nova::nifs::tests::prepare_simple_fold_inputs; use crate::folding::nova::{ ivc::get_committed_instance_coordinates, nifs::NIFS, traits::NovaR1CS, Witness, }; use crate::frontend::tests::CubicFCircuit; - use crate::pedersen::Pedersen; use crate::transcript::poseidon::tests::poseidon_test_config; #[test]
@@ -18,13 +18,13 @@ use ark_std::{One, Zero};
use core::{borrow::Borrow, marker::PhantomData}; use crate::ccs::r1cs::R1CS; +use crate::commitment::pedersen::Params as PedersenParams; use crate::folding::nova::{ circuits::{CommittedInstanceVar, CF1, CF2}, ivc::IVC, CommittedInstance, Witness, }; use crate::frontend::FCircuit; -use crate::pedersen::Params as PedersenParams; use crate::utils::gadgets::{ hadamard, mat_vec_mul_sparse, vec_add, vec_scalar_mul, SparseMatrixVar, };@@ -355,8 +355,8 @@ #[cfg(not(test))]
{ // imports here instead of at the top of the file, so we avoid having multiple // `#[cfg(not(test))] + use crate::commitment::pedersen::PedersenGadget; use crate::folding::nova::cyclefold::{CycleFoldCommittedInstanceVar, CF_IO_LEN}; - use crate::pedersen::PedersenGadget; use ark_r1cs_std::ToBitsGadget; let cf_r1cs = R1CSVar::<
@@ -14,8 +14,8 @@ };
use super::{nifs::NIFS, traits::NovaR1CS, CommittedInstance, Witness}; use crate::ccs::r1cs::R1CS; use crate::ccs::r1cs::{extract_r1cs, extract_w_x}; +use crate::commitment::pedersen::{Params as PedersenParams, Pedersen}; use crate::frontend::FCircuit; -use crate::pedersen::{Params as PedersenParams, Pedersen}; use crate::Error; #[cfg(test)]
@@ -7,8 +7,11 @@ use ark_ec::{CurveGroup, Group};
use ark_std::fmt::Debug; use ark_std::{One, Zero}; +use crate::commitment::{ + pedersen::{Params as PedersenParams, Pedersen}, + CommitmentProver, +}; use crate::folding::circuits::nonnative::point_to_nonnative_limbs; -use crate::pedersen::{Params as PedersenParams, Pedersen}; use crate::utils::vec::is_zero_vec; use crate::Error;@@ -89,11 +92,13 @@ where
<C as Group>::ScalarField: Absorb, { pub fn new(w: Vec<C::ScalarField>, e_len: usize) -> Self { + // note: at the current version, we don't use the blinding factors and we set them to 0 + // always. Self { E: vec![C::ScalarField::zero(); e_len], - rE: C::ScalarField::zero(), // because we use C::zero() as cmE + rE: C::ScalarField::zero(), W: w, - rW: C::ScalarField::one(), + rW: C::ScalarField::zero(), } } pub fn commit(
@@ -5,7 +5,10 @@ use std::marker::PhantomData;
use super::{CommittedInstance, Witness}; use crate::ccs::r1cs::R1CS; -use crate::pedersen::{Params as PedersenParams, Pedersen, Proof as PedersenProof}; +use crate::commitment::{ + pedersen::{Params as PedersenParams, Pedersen, Proof as PedersenProof}, + CommitmentProver, +}; use crate::transcript::Transcript; use crate::utils::vec::*; use crate::Error;
@@ -369,7 +369,7 @@ use ark_pallas::{Fr, Projective};
use ark_std::UniformRand; use crate::ccs::r1cs::tests::{get_test_r1cs, get_test_z}; - use crate::pedersen::Pedersen; + use crate::commitment::{pedersen::Pedersen, CommitmentProver}; use crate::transcript::poseidon::{tests::poseidon_test_config, PoseidonTranscript}; pub(crate) fn check_instance<C: CurveGroup>(
@@ -9,10 +9,10 @@
pub mod transcript; use transcript::Transcript; pub mod ccs; +pub mod commitment; pub mod constants; pub mod folding; pub mod frontend; -pub mod pedersen; pub mod utils; #[derive(Debug, Error)]@@ -21,6 +21,10 @@ #[error("ark_relations::r1cs::SynthesisError")]
SynthesisError(#[from] ark_relations::r1cs::SynthesisError), #[error("ark_serialize::SerializationError")] SerializationError(#[from] ark_serialize::SerializationError), + #[error("ark_poly_commit::Error")] + PolyCommitError(#[from] ark_poly_commit::Error), + #[error("crate::utils::espresso::virtual_polynomial::ArithErrors")] + ArithError(#[from] utils::espresso::virtual_polynomial::ArithErrors), #[error("{0}")] Other(String),@@ -36,8 +40,8 @@ #[error("Can not be empty")]
Empty, #[error("Pedersen parameters length is not suficient (generators.len={0} < vector.len={1} unsatisfied)")] PedersenParamsLen(usize, usize), - #[error("Pedersen verification failed")] - PedersenVerificationFail, + #[error("Commitment verification failed")] + CommitmentVerificationFail, #[error("IVC verification failed")] IVCVerificationFail, #[error("R1CS instance is expected to not be relaxed")]@@ -52,6 +56,8 @@ #[error("Value out of bounds")]
OutOfBounds, #[error("Could not construct the Evaluation Domain")] NewDomainFail, + #[error("Feature '{0}' not supported yet")] + NotSupportedYet(String), #[error(transparent)] ProtoGalaxy(folding::protogalaxy::ProtoGalaxyError),
@@ -5,9 +5,9 @@ use ark_relations::r1cs::SynthesisError;
use ark_std::{rand::Rng, UniformRand}; use core::marker::PhantomData; -use crate::utils::vec::{vec_add, vec_scalar_mul}; - +use super::CommitmentProver; use crate::transcript::Transcript; +use crate::utils::vec::{vec_add, vec_scalar_mul}; use crate::Error; #[derive(Debug, Clone, Eq, PartialEq)]@@ -39,11 +39,16 @@ generators,
}; params } +} - pub fn commit( - params: &Params<C>, - v: &Vec<C::ScalarField>, - r: &C::ScalarField, +// implement the CommitmentProver trait for Pedersen +impl<C: CurveGroup> CommitmentProver<C> for Pedersen<C> { + type Params = Params<C>; + type Proof = Proof<C>; + fn commit( + params: &Self::Params, + v: &[C::ScalarField], + r: &C::ScalarField, // blinding factor ) -> Result<C, Error> { if params.generators.len() < v.len() { return Err(Error::PedersenParamsLen(params.generators.len(), v.len()));@@ -53,13 +58,13 @@ // use msm_unchecked because we already ensured at the if that lengths match
Ok(params.h.mul(r) + C::msm_unchecked(¶ms.generators[..v.len()], v)) } - pub fn prove( + fn prove( params: &Params<C>, transcript: &mut impl Transcript<C>, cm: &C, - v: &Vec<C::ScalarField>, - r: &C::ScalarField, - ) -> Result<Proof<C>, Error> { + v: &[C::ScalarField], + r: &C::ScalarField, // blinding factor + ) -> Result<Self::Proof, Error> { if params.generators.len() < v.len() { return Err(Error::PedersenParamsLen(params.generators.len(), v.len())); }@@ -80,9 +85,11 @@ let u = vec_add(&vec_scalar_mul(v, &e), &d)?;
// r_u = e⋅r + r_1 let r_u = e * r + r1; - Ok(Proof::<C> { R, u, r_u }) + Ok(Self::Proof { R, u, r_u }) } +} +impl<C: CurveGroup> Pedersen<C> { pub fn verify( params: &Params<C>, transcript: &mut impl Transcript<C>,@@ -102,13 +109,13 @@ transcript.get_challenges(proof.u.len()); // d
transcript.absorb_point(&proof.R)?; let e = transcript.get_challenge(); - // check that: R + cm == h⋅r_u + <g, u> + // check that: R + cm⋅e == h⋅r_u + <g, u> let lhs = proof.R + cm.mul(e); // use msm_unchecked because we already ensured at the if that lengths match let rhs = params.h.mul(proof.r_u) + C::msm_unchecked(¶ms.generators[..proof.u.len()], &proof.u); if lhs != rhs { - return Err(Error::PedersenVerificationFail); + return Err(Error::CommitmentVerificationFail); } Ok(()) }@@ -164,7 +171,7 @@ #[test]
fn test_pedersen_vector() { let mut rng = ark_std::test_rng(); - const n: usize = 10; + let n: usize = 10; // setup params let params = Pedersen::<Projective>::new_params(&mut rng, n); let poseidon_config = poseidon_test_config::<Fr>();@@ -187,7 +194,7 @@ #[test]
fn test_pedersen_circuit() { let mut rng = ark_std::test_rng(); - const n: usize = 10; + let n: usize = 10; // setup params let params = Pedersen::<Projective>::new_params(&mut rng, n);