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