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(params.generators.len(), v.len()));
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(params.generators.len(), v.len()));
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 params.generators.len(),
92 proof.u.len(),
93 ));
94 }
95
96 transcript.absorb_point(&cm)?;
97 transcript.get_challenge(); // r_1
98 transcript.get_challenges(proof.u.len()); // d
99 transcript.absorb_point(&proof.R)?;
100 let e = transcript.get_challenge();
101
102 // check that: R + cm == h⋅r_u + <g, u>
103 let lhs = proof.R + cm.mul(e);
104 // use msm_unchecked because we already ensured at the if that lengths match
105 let rhs = params.h.mul(proof.r_u)
106 + C::msm_unchecked(¶ms.generators[..proof.u.len()], &proof.u);
107 if lhs != rhs {
108 return Err(Error::PedersenVerificationFail);
109 }
110 Ok(())
111 }
112}
113
114#[cfg(test)]
115mod tests {
116 use super::*;
117 use crate::transcript::poseidon::{tests::poseidon_test_config, PoseidonTranscript};
118
119 use ark_pallas::{Fr, Projective};
120
121 #[test]
122 fn test_pedersen_vector() {
123 let mut rng = ark_std::test_rng();
124
125 const n: usize = 10;
126 // setup params
127 let params = Pedersen::<Projective>::new_params(&mut rng, n);
128 let poseidon_config = poseidon_test_config::<Fr>();
129
130 // init Prover's transcript
131 let mut transcript_p = PoseidonTranscript::<Projective>::new(&poseidon_config);
132 // init Verifier's transcript
133 let mut transcript_v = PoseidonTranscript::<Projective>::new(&poseidon_config);
134
135 let v: Vec<Fr> = std::iter::repeat_with(|| Fr::rand(&mut rng))
136 .take(n)
137 .collect();
138 let r: Fr = Fr::rand(&mut rng);
139 let cm = Pedersen::<Projective>::commit(¶ms, &v, &r).unwrap();
140 let proof = Pedersen::<Projective>::prove(¶ms, &mut transcript_p, &cm, &v, &r).unwrap();
141 Pedersen::<Projective>::verify(¶ms, &mut transcript_v, cm, proof).unwrap();
142 }
143}