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