arnaucube
arnaucube/sonobePublic Self-hosted repository
sonobe/folding-schemes/src/commitment/pedersen.rs
folding-schemes/src/commitment/pedersen.rsRaw
  1use ark_ec::CurveGroup;
  2use ark_ff::Field;
  3use ark_r1cs_std::{boolean::Boolean, groups::GroupOpsBounds, prelude::CurveVar};
  4use ark_relations::r1cs::SynthesisError;
  5use ark_std::Zero;
  6use ark_std::{rand::RngCore, UniformRand};
  7use core::marker::PhantomData;
  8
  9use super::CommitmentScheme;
 10use crate::transcript::Transcript;
 11use crate::utils::vec::{vec_add, vec_scalar_mul};
 12use crate::Error;
 13
 14#[derive(Debug, Clone, Eq, PartialEq)]
 15pub struct Proof<C: CurveGroup> {
 16    pub R: C,
 17    pub u: Vec<C::ScalarField>,
 18    pub r_u: C::ScalarField, // blind
 19}
 20
 21#[derive(Debug, Clone, Eq, PartialEq)]
 22pub struct Params<C: CurveGroup> {
 23    pub h: C,
 24    pub generators: Vec<C::Affine>,
 25}
 26
 27#[derive(Debug, Clone, Eq, PartialEq)]
 28pub struct Pedersen<C: CurveGroup, const H: bool = false> {
 29    _c: PhantomData<C>,
 30}
 31
 32/// Implements the CommitmentScheme trait for Pedersen commitments
 33impl<C: CurveGroup, const H: bool> CommitmentScheme<C, H> for Pedersen<C, H> {
 34    type ProverParams = Params<C>;
 35    type VerifierParams = Params<C>;
 36    type Proof = Proof<C>;
 37    type ProverChallenge = (C::ScalarField, Vec<C::ScalarField>, C, C::ScalarField);
 38    type Challenge = C::ScalarField;
 39
 40    fn setup(
 41        mut rng: impl RngCore,
 42        len: usize,
 43    ) -> Result<(Self::ProverParams, Self::VerifierParams), Error> {
 44        let generators: Vec<C::Affine> = std::iter::repeat_with(|| C::Affine::rand(&mut rng))
 45            .take(len.next_power_of_two())
 46            .collect();
 47        let p = Params::<C> {
 48            h: C::rand(&mut rng),
 49            generators,
 50        };
 51        Ok((p.clone(), p))
 52    }
 53
 54    fn commit(
 55        params: &Self::ProverParams,
 56        v: &[C::ScalarField],
 57        r: &C::ScalarField, // blinding factor
 58    ) -> Result<C, Error> {
 59        if params.generators.len() < v.len() {
 60            return Err(Error::PedersenParamsLen(params.generators.len(), v.len()));
 61        }
 62        if !H && (!r.is_zero()) {
 63            return Err(Error::BlindingNotZero);
 64        }
 65
 66        // h⋅r + <g, v>
 67        // use msm_unchecked because we already ensured at the if that lengths match
 68        if !H {
 69            return Ok(C::msm_unchecked(&params.generators[..v.len()], v));
 70        }
 71        Ok(params.h.mul(r) + C::msm_unchecked(&params.generators[..v.len()], v))
 72    }
 73
 74    fn prove(
 75        params: &Self::ProverParams,
 76        transcript: &mut impl Transcript<C>,
 77        cm: &C,
 78        v: &[C::ScalarField],
 79        r: &C::ScalarField, // blinding factor
 80        _rng: Option<&mut dyn RngCore>,
 81    ) -> Result<Self::Proof, Error> {
 82        transcript.absorb_point(cm)?;
 83        let r1 = transcript.get_challenge();
 84        let d = transcript.get_challenges(v.len());
 85
 86        // R = h⋅r_1 + <g, d>
 87        // use msm_unchecked because we already ensured at the if that lengths match
 88        let mut R: C = C::msm_unchecked(&params.generators[..d.len()], &d);
 89        if H {
 90            R += params.h.mul(r1);
 91        }
 92
 93        transcript.absorb_point(&R)?;
 94        let e = transcript.get_challenge();
 95
 96        let challenge = (r1, d, R, e);
 97        Self::prove_with_challenge(params, challenge, v, r, _rng)
 98    }
 99
100    fn prove_with_challenge(
101        params: &Self::ProverParams,
102        challenge: Self::ProverChallenge,
103        v: &[C::ScalarField], // vector
104        r: &C::ScalarField,   // blinding factor
105        _rng: Option<&mut dyn RngCore>,
106    ) -> Result<Self::Proof, Error> {
107        if params.generators.len() < v.len() {
108            return Err(Error::PedersenParamsLen(params.generators.len(), v.len()));
109        }
110        if !H && (!r.is_zero()) {
111            return Err(Error::BlindingNotZero);
112        }
113        let (r1, d, R, e): (C::ScalarField, Vec<C::ScalarField>, C, C::ScalarField) = challenge;
114
115        // u = d + v⋅e
116        let u = vec_add(&vec_scalar_mul(v, &e), &d)?;
117        // r_u = e⋅r + r_1
118        let mut r_u = C::ScalarField::zero();
119        if H {
120            r_u = e * r + r1;
121        }
122
123        Ok(Self::Proof { R, u, r_u })
124    }
125
126    fn verify(
127        params: &Self::VerifierParams,
128        transcript: &mut impl Transcript<C>,
129        cm: &C,
130        proof: &Proof<C>,
131    ) -> Result<(), Error> {
132        transcript.absorb_point(cm)?;
133        transcript.get_challenge(); // r_1
134        transcript.get_challenges(proof.u.len()); // d
135        transcript.absorb_point(&proof.R)?;
136        let e = transcript.get_challenge();
137        Self::verify_with_challenge(params, e, cm, proof)
138    }
139
140    fn verify_with_challenge(
141        params: &Self::VerifierParams,
142        challenge: Self::Challenge,
143        cm: &C,
144        proof: &Proof<C>,
145    ) -> Result<(), Error> {
146        if params.generators.len() < proof.u.len() {
147            return Err(Error::PedersenParamsLen(
148                params.generators.len(),
149                proof.u.len(),
150            ));
151        }
152        if !H && (!proof.r_u.is_zero()) {
153            return Err(Error::BlindingNotZero);
154        }
155
156        let e = challenge;
157
158        // check that: R + cm⋅e == h⋅r_u + <g, u>
159        let lhs = proof.R + cm.mul(e);
160        // use msm_unchecked because we already ensured at the if that lengths match
161        let mut rhs = C::msm_unchecked(&params.generators[..proof.u.len()], &proof.u);
162        if H {
163            rhs += params.h.mul(proof.r_u);
164        }
165        if lhs != rhs {
166            return Err(Error::CommitmentVerificationFail);
167        }
168        Ok(())
169    }
170}
171
172pub type CF<C> = <<C as CurveGroup>::BaseField as Field>::BasePrimeField;
173
174pub struct PedersenGadget<C, GC, const H: bool = false>
175where
176    C: CurveGroup,
177    GC: CurveVar<C, CF<C>>,
178{
179    _cf: PhantomData<CF<C>>,
180    _c: PhantomData<C>,
181    _gc: PhantomData<GC>,
182}
183
184use ark_r1cs_std::ToBitsGadget;
185impl<C, GC, const H: bool> PedersenGadget<C, GC, H>
186where
187    C: CurveGroup,
188    GC: CurveVar<C, CF<C>>,
189
190    <C as ark_ec::CurveGroup>::BaseField: ark_ff::PrimeField,
191    for<'a> &'a GC: GroupOpsBounds<'a, C, GC>,
192{
193    pub fn commit(
194        h: GC,
195        g: Vec<GC>,
196        v: Vec<Vec<Boolean<CF<C>>>>,
197        r: Vec<Boolean<CF<C>>>,
198    ) -> Result<GC, SynthesisError> {
199        let mut res = GC::zero();
200        if H {
201            res += h.scalar_mul_le(r.iter())?;
202        }
203        for (i, v_i) in v.iter().enumerate() {
204            res += g[i].scalar_mul_le(v_i.to_bits_le()?.iter())?;
205        }
206        Ok(res)
207    }
208}
209
210#[cfg(test)]
211mod tests {
212    use ark_ff::{BigInteger, PrimeField};
213    use ark_pallas::{constraints::GVar, Fq, Fr, Projective};
214    use ark_r1cs_std::{alloc::AllocVar, eq::EqGadget};
215    use ark_relations::r1cs::ConstraintSystem;
216    use ark_std::UniformRand;
217
218    use super::*;
219    use crate::transcript::poseidon::{poseidon_canonical_config, PoseidonTranscript};
220
221    #[test]
222    fn test_pedersen() {
223        test_pedersen_opt::<false>();
224        test_pedersen_opt::<true>();
225    }
226    fn test_pedersen_opt<const hiding: bool>() {
227        let mut rng = ark_std::test_rng();
228
229        let n: usize = 10;
230        // setup params
231        let (params, _) = Pedersen::<Projective>::setup(&mut rng, n).unwrap();
232        let poseidon_config = poseidon_canonical_config::<Fr>();
233
234        // init Prover's transcript
235        let mut transcript_p = PoseidonTranscript::<Projective>::new(&poseidon_config);
236        // init Verifier's transcript
237        let mut transcript_v = PoseidonTranscript::<Projective>::new(&poseidon_config);
238
239        let v: Vec<Fr> = std::iter::repeat_with(|| Fr::rand(&mut rng))
240            .take(n)
241            .collect();
242        // blinding factor
243        let r: Fr = if hiding {
244            Fr::rand(&mut rng)
245        } else {
246            Fr::zero()
247        };
248        let cm = Pedersen::<Projective, hiding>::commit(&params, &v, &r).unwrap();
249        let proof =
250            Pedersen::<Projective, hiding>::prove(&params, &mut transcript_p, &cm, &v, &r, None)
251                .unwrap();
252        Pedersen::<Projective, hiding>::verify(&params, &mut transcript_v, &cm, &proof).unwrap();
253    }
254
255    #[test]
256    fn test_pedersen_circuit() {
257        test_pedersen_circuit_opt::<false>();
258        test_pedersen_circuit_opt::<true>();
259    }
260    fn test_pedersen_circuit_opt<const hiding: bool>() {
261        let mut rng = ark_std::test_rng();
262
263        let n: usize = 8;
264        // setup params
265        let (params, _) = Pedersen::<Projective, hiding>::setup(&mut rng, n).unwrap();
266
267        let v: Vec<Fr> = std::iter::repeat_with(|| Fr::rand(&mut rng))
268            .take(n)
269            .collect();
270        // blinding factor
271        let r: Fr = if hiding {
272            Fr::rand(&mut rng)
273        } else {
274            Fr::zero()
275        };
276        let cm = Pedersen::<Projective, hiding>::commit(&params, &v, &r).unwrap();
277
278        let v_bits: Vec<Vec<bool>> = v.iter().map(|val| val.into_bigint().to_bits_le()).collect();
279        let r_bits: Vec<bool> = r.into_bigint().to_bits_le();
280
281        // circuit
282        let cs = ConstraintSystem::<Fq>::new_ref();
283
284        // prepare inputs
285        let vVar: Vec<Vec<Boolean<Fq>>> = v_bits
286            .iter()
287            .map(|val_bits| {
288                Vec::<Boolean<Fq>>::new_witness(cs.clone(), || Ok(val_bits.clone())).unwrap()
289            })
290            .collect();
291        let rVar = Vec::<Boolean<Fq>>::new_witness(cs.clone(), || Ok(r_bits)).unwrap();
292        let gVar = Vec::<GVar>::new_witness(cs.clone(), || Ok(params.generators)).unwrap();
293        let hVar = GVar::new_witness(cs.clone(), || Ok(params.h)).unwrap();
294        let expected_cmVar = GVar::new_witness(cs.clone(), || Ok(cm)).unwrap();
295
296        // use the gadget
297        let cmVar =
298            PedersenGadget::<Projective, GVar, hiding>::commit(hVar, gVar, vVar, rVar).unwrap();
299        cmVar.enforce_equal(&expected_cmVar).unwrap();
300    }
301}