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