sonobe/src/pedersen.rs
src/pedersen.rsRaw
1use ark_ec::CurveGroup;
2use ark_std::{rand::Rng, UniformRand};
3use std::marker::PhantomData;
4
5use crate::utils::vec::{vec_add, vec_scalar_mul};
6
7use crate::transcript::Transcript;
8use crate::Error;
9
10#[derive(Debug, Clone, Eq, PartialEq)]
11pub struct Proof<C: CurveGroup> {
12 R: C,
13 u: Vec<C::ScalarField>,
14 r_u: C::ScalarField,
15}
16
17#[derive(Debug, Clone, Eq, PartialEq)]
18pub struct Params<C: CurveGroup> {
19 h: C,
20 pub generators: Vec<C::Affine>,
21}
22
23#[derive(Debug, Clone, Eq, PartialEq)]
24pub struct Pedersen<C: CurveGroup> {
25 _c: PhantomData<C>,
26}
27
28impl<C: CurveGroup> Pedersen<C> {
29 pub fn new_params<R: Rng>(rng: &mut R, max: usize) -> Params<C> {
30 let generators: Vec<C::Affine> = std::iter::repeat_with(|| C::Affine::rand(rng))
31 .take(max.next_power_of_two())
32 .collect();
33 let params: Params<C> = Params::<C> {
34 h: C::rand(rng),
35 generators,
36 };
37 params
38 }
39
40 pub fn commit(
41 params: &Params<C>,
42 v: &Vec<C::ScalarField>,
43 r: &C::ScalarField,
44 ) -> Result<C, Error> {
45 if params.generators.len() < v.len() {
46 return Err(Error::PedersenParamsLen);
47 }
48 // h⋅r + <g, v>
49 // use msm_unchecked because we already ensured at the if that lengths match
50 Ok(params.h.mul(r) + C::msm_unchecked(¶ms.generators[..v.len()], v))
51 }
52
53 pub fn prove(
54 params: &Params<C>,
55 transcript: &mut impl Transcript<C>,
56 cm: &C,
57 v: &Vec<C::ScalarField>,
58 r: &C::ScalarField,
59 ) -> Result<Proof<C>, Error> {
60 if params.generators.len() < v.len() {
61 return Err(Error::PedersenParamsLen);
62 }
63
64 transcript.absorb_point(cm);
65 let r1 = transcript.get_challenge();
66 let d = transcript.get_challenges(v.len());
67
68 // R = h⋅r_1 + <g, d>
69 // use msm_unchecked because we already ensured at the if that lengths match
70 let R: C = params.h.mul(r1) + C::msm_unchecked(¶ms.generators[..d.len()], &d);
71
72 transcript.absorb_point(&R);
73 let e = transcript.get_challenge();
74
75 // u = d + v⋅e
76 let u = vec_add(&vec_scalar_mul(v, &e), &d)?;
77 // r_u = e⋅r + r_1
78 let r_u = e * r + r1;
79
80 Ok(Proof::<C> { R, u, r_u })
81 }
82
83 pub fn verify(
84 params: &Params<C>,
85 transcript: &mut impl Transcript<C>,
86 cm: C,
87 proof: Proof<C>,
88 ) -> Result<(), Error> {
89 if params.generators.len() < proof.u.len() {
90 return Err(Error::PedersenParamsLen);
91 }
92
93 transcript.absorb_point(&cm);
94 transcript.get_challenge(); // r_1
95 transcript.get_challenges(proof.u.len()); // d
96 transcript.absorb_point(&proof.R);
97 let e = transcript.get_challenge();
98
99 // check that: R + cm == h⋅r_u + <g, u>
100 let lhs = proof.R + cm.mul(e);
101 // use msm_unchecked because we already ensured at the if that lengths match
102 let rhs = params.h.mul(proof.r_u)
103 + C::msm_unchecked(¶ms.generators[..proof.u.len()], &proof.u);
104 if lhs != rhs {
105 return Err(Error::PedersenVerificationFail);
106 }
107 Ok(())
108 }
109}
110
111#[cfg(test)]
112mod tests {
113 use super::*;
114 use crate::transcript::poseidon::{tests::poseidon_test_config, PoseidonTranscript};
115
116 use ark_pallas::{Fr, Projective};
117
118 #[test]
119 fn test_pedersen_vector() {
120 let mut rng = ark_std::test_rng();
121
122 const n: usize = 10;
123 // setup params
124 let params = Pedersen::<Projective>::new_params(&mut rng, n);
125 let poseidon_config = poseidon_test_config::<Fr>();
126
127 // init Prover's transcript
128 let mut transcript_p = PoseidonTranscript::<Projective>::new(&poseidon_config);
129 // init Verifier's transcript
130 let mut transcript_v = PoseidonTranscript::<Projective>::new(&poseidon_config);
131
132 let v: Vec<Fr> = vec![Fr::rand(&mut rng); n];
133 let r: Fr = Fr::rand(&mut rng);
134 let cm = Pedersen::<Projective>::commit(¶ms, &v, &r).unwrap();
135 let proof = Pedersen::<Projective>::prove(¶ms, &mut transcript_p, &cm, &v, &r).unwrap();
136 Pedersen::<Projective>::verify(¶ms, &mut transcript_v, cm, proof).unwrap();
137 }
138}