arnaucube
arnaucube/nova-studyPublic Self-hosted repository
nova-study/src/pedersen.rs
src/pedersen.rsRaw
  1use ark_ec::AffineRepr;
  2use ark_ec::CurveGroup;
  3use ark_std::{
  4    rand::{Rng, RngCore},
  5    UniformRand,
  6};
  7use std::marker::PhantomData;
  8
  9use crate::transcript::Transcript;
 10use crate::utils::{naive_msm, vec_add, vector_elem_product};
 11
 12pub struct Proof_elem<C: CurveGroup> {
 13    R: C,
 14    t1: C::ScalarField,
 15    t2: C::ScalarField,
 16}
 17pub struct Proof<C: CurveGroup> {
 18    R: C,
 19    u_: Vec<C::ScalarField>,
 20    ru_: C::ScalarField,
 21}
 22
 23pub struct Params<C: CurveGroup> {
 24    g: C,
 25    h: C,
 26    pub generators: Vec<C>,
 27}
 28
 29pub struct Pedersen<C: CurveGroup> {
 30    _phantom: PhantomData<C>,
 31}
 32
 33impl<C: CurveGroup> Pedersen<C> {
 34    pub fn new_params<R: Rng>(rng: &mut R, max: usize) -> Params<C> {
 35        let h_scalar = C::ScalarField::rand(rng);
 36        let g: C = C::generator();
 37        let generators: Vec<C> = vec![C::rand(rng); max];
 38        let params: Params<C> = Params::<C> {
 39            g,
 40            h: g.mul(h_scalar),
 41            generators,
 42        };
 43        params
 44    }
 45
 46    pub fn commit_elem<R: RngCore>(
 47        rng: &mut R,
 48        params: &Params<C>,
 49        v: &C::ScalarField,
 50    ) -> CommitmentElem<C> {
 51        let r = C::ScalarField::rand(rng);
 52        let cm: C = (params.g.mul(v) + params.h.mul(r));
 53        CommitmentElem::<C> { cm, r }
 54    }
 55    pub fn commit(
 56        params: &Params<C>,
 57        v: &Vec<C::ScalarField>,
 58        r: &C::ScalarField, // random value is provided, in order to be choosen by other parts of the protocol
 59    ) -> Commitment<C> {
 60        let cm = params.h.mul(r) + naive_msm(v, &params.generators);
 61        Commitment::<C>(cm)
 62    }
 63
 64    pub fn prove_elem(
 65        params: &Params<C>,
 66        transcript: &mut Transcript<C::ScalarField>,
 67        cm: C,
 68        v: C::ScalarField,
 69        r: C::ScalarField,
 70    ) -> Proof_elem<C> {
 71        let r1 = transcript.get_challenge(b"r_1");
 72        let r2 = transcript.get_challenge(b"r_2");
 73
 74        let R: C = (params.g.mul(r1) + params.h.mul(r2));
 75
 76        transcript.add(b"cm", &cm);
 77        transcript.add(b"R", &R);
 78        let e = transcript.get_challenge(b"e");
 79
 80        let t1 = r1 + v * e;
 81        let t2 = r2 + r * e;
 82
 83        Proof_elem::<C> { R, t1, t2 }
 84    }
 85    pub fn prove(
 86        params: &Params<C>,
 87        transcript: &mut Transcript<C::ScalarField>,
 88        cm: &Commitment<C>, // TODO maybe it makes sense to not have a type wrapper and use directly C
 89        v: &Vec<C::ScalarField>,
 90        r: &C::ScalarField,
 91    ) -> Proof<C> {
 92        let r1 = transcript.get_challenge(b"r_1");
 93        let d = transcript.get_challenge_vec(b"d", v.len());
 94
 95        let R: C = params.h.mul(r1) + naive_msm(&d, &params.generators);
 96
 97        transcript.add(b"cm", &cm.0);
 98        transcript.add(b"R", &R);
 99        let e = transcript.get_challenge(b"e");
100
101        let u_ = vec_add(&vector_elem_product(&v, &e), &d);
102        let ru_ = e * r + r1;
103
104        Proof::<C> { R, u_, ru_ }
105    }
106    pub fn verify(
107        params: &Params<C>,
108        transcript: &mut Transcript<C::ScalarField>,
109        cm: Commitment<C>,
110        proof: Proof<C>,
111    ) -> bool {
112        // r1, d just to match Prover's transcript
113        transcript.get_challenge(b"r_1");
114        transcript.get_challenge_vec(b"d", proof.u_.len());
115
116        transcript.add(b"cm", &cm.0);
117        transcript.add(b"R", &proof.R);
118        let e = transcript.get_challenge(b"e");
119        let lhs = proof.R + cm.0.mul(e);
120        let rhs = params.h.mul(proof.ru_) + naive_msm(&proof.u_, &params.generators);
121        if lhs != rhs {
122            return false;
123        }
124        true
125    }
126
127    pub fn verify_elem(
128        params: &Params<C>,
129        transcript: &mut Transcript<C::ScalarField>,
130        cm: C,
131        proof: Proof_elem<C>,
132    ) -> bool {
133        // s1, s2 just to match Prover's transcript
134        transcript.get_challenge(b"r_1");
135        transcript.get_challenge(b"r_2");
136
137        transcript.add(b"cm", &cm);
138        transcript.add(b"R", &proof.R);
139        let e = transcript.get_challenge(b"e");
140        let lhs = proof.R + cm.mul(e);
141        let rhs = params.g.mul(proof.t1) + params.h.mul(proof.t2);
142        if lhs != rhs {
143            return false;
144        }
145        true
146    }
147}
148
149#[derive(Clone, Debug)]
150pub struct Commitment<C: CurveGroup>(pub C);
151
152pub struct CommitmentElem<C: CurveGroup> {
153    pub cm: C,
154    pub r: C::ScalarField,
155}
156impl<C: CurveGroup> CommitmentElem<C> {
157    pub fn prove(
158        &self,
159        params: &Params<C>,
160        transcript: &mut Transcript<C::ScalarField>,
161        v: C::ScalarField,
162    ) -> Proof_elem<C> {
163        Pedersen::<C>::prove_elem(params, transcript, self.cm, v, self.r)
164    }
165}
166
167#[cfg(test)]
168mod tests {
169    use super::*;
170    use ark_ec::CurveGroup;
171    use ark_mnt4_298::{Fr, G1Projective};
172    use std::ops::Mul;
173
174    #[test]
175    fn test_pedersen_single_element() {
176        let mut rng = ark_std::test_rng();
177
178        // setup params
179        let params = Pedersen::<G1Projective>::new_params(
180            &mut rng, 0, /* 0, as here we don't use commit_vec */
181        );
182
183        // init Prover's transcript
184        let mut transcript_p: Transcript<Fr> = Transcript::<Fr>::new();
185        // init Verifier's transcript
186        let mut transcript_v: Transcript<Fr> = Transcript::<Fr>::new();
187
188        let v = Fr::rand(&mut rng);
189
190        let cm = Pedersen::commit_elem(&mut rng, &params, &v);
191        let proof = cm.prove(&params, &mut transcript_p, v);
192        // also can use:
193        // let proof = Pedersen::prove_elem(&params, &mut transcript_p, cm.cm, v, cm.r);
194        let v = Pedersen::verify_elem(&params, &mut transcript_v, cm.cm, proof);
195        assert!(v);
196    }
197    #[test]
198    fn test_pedersen_vector() {
199        let mut rng = ark_std::test_rng();
200
201        const n: usize = 10;
202        // setup params
203        let params = Pedersen::<G1Projective>::new_params(&mut rng, n);
204
205        // init Prover's transcript
206        let mut transcript_p: Transcript<Fr> = Transcript::<Fr>::new();
207        // init Verifier's transcript
208        let mut transcript_v: Transcript<Fr> = Transcript::<Fr>::new();
209
210        let v: Vec<Fr> = vec![Fr::rand(&mut rng); n];
211        let r: Fr = Fr::rand(&mut rng);
212        let cm = Pedersen::commit(&params, &v, &r);
213        let proof = Pedersen::prove(&params, &mut transcript_p, &cm, &v, &r);
214        let v = Pedersen::verify(&params, &mut transcript_v, cm, proof);
215        assert!(v);
216    }
217}