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