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