sonobe/src/pedersen.rs
src/pedersen.rsRaw
1use ark_ec::CurveGroup;
2use ark_ff::Field;
3use ark_r1cs_std::{boolean::Boolean, groups::GroupOpsBounds, prelude::CurveVar};
4use ark_relations::r1cs::SynthesisError;
5use ark_std::{rand::Rng, UniformRand};
6use core::marker::PhantomData;
7
8use crate::utils::vec::{vec_add, vec_scalar_mul};
9
10use crate::transcript::Transcript;
11use crate::Error;
12
13#[derive(Debug, Clone, Eq, PartialEq)]
14pub struct Proof<C: CurveGroup> {
15 pub R: C,
16 pub u: Vec<C::ScalarField>,
17 pub r_u: C::ScalarField,
18}
19
20#[derive(Debug, Clone, Eq, PartialEq)]
21pub struct Params<C: CurveGroup> {
22 pub h: C,
23 pub generators: Vec<C::Affine>,
24}
25
26#[derive(Debug, Clone, Eq, PartialEq)]
27pub struct Pedersen<C: CurveGroup> {
28 _c: PhantomData<C>,
29}
30
31impl<C: CurveGroup> Pedersen<C> {
32 pub fn new_params<R: Rng>(rng: &mut R, max: usize) -> Params<C> {
33 let generators: Vec<C::Affine> = std::iter::repeat_with(|| C::Affine::rand(rng))
34 .take(max.next_power_of_two())
35 .collect();
36 let params: Params<C> = Params::<C> {
37 h: C::rand(rng),
38 generators,
39 };
40 params
41 }
42
43 pub fn commit(
44 params: &Params<C>,
45 v: &Vec<C::ScalarField>,
46 r: &C::ScalarField,
47 ) -> Result<C, Error> {
48 if params.generators.len() < v.len() {
49 return Err(Error::PedersenParamsLen(params.generators.len(), v.len()));
50 }
51 // h⋅r + <g, v>
52 // use msm_unchecked because we already ensured at the if that lengths match
53 Ok(params.h.mul(r) + C::msm_unchecked(¶ms.generators[..v.len()], v))
54 }
55
56 pub fn prove(
57 params: &Params<C>,
58 transcript: &mut impl Transcript<C>,
59 cm: &C,
60 v: &Vec<C::ScalarField>,
61 r: &C::ScalarField,
62 ) -> Result<Proof<C>, Error> {
63 if params.generators.len() < v.len() {
64 return Err(Error::PedersenParamsLen(params.generators.len(), v.len()));
65 }
66
67 transcript.absorb_point(cm)?;
68 let r1 = transcript.get_challenge();
69 let d = transcript.get_challenges(v.len());
70
71 // R = h⋅r_1 + <g, d>
72 // use msm_unchecked because we already ensured at the if that lengths match
73 let R: C = params.h.mul(r1) + C::msm_unchecked(¶ms.generators[..d.len()], &d);
74
75 transcript.absorb_point(&R)?;
76 let e = transcript.get_challenge();
77
78 // u = d + v⋅e
79 let u = vec_add(&vec_scalar_mul(v, &e), &d)?;
80 // r_u = e⋅r + r_1
81 let r_u = e * r + r1;
82
83 Ok(Proof::<C> { R, u, r_u })
84 }
85
86 pub fn verify(
87 params: &Params<C>,
88 transcript: &mut impl Transcript<C>,
89 cm: C,
90 proof: Proof<C>,
91 ) -> Result<(), Error> {
92 if params.generators.len() < proof.u.len() {
93 return Err(Error::PedersenParamsLen(
94 params.generators.len(),
95 proof.u.len(),
96 ));
97 }
98
99 transcript.absorb_point(&cm)?;
100 transcript.get_challenge(); // r_1
101 transcript.get_challenges(proof.u.len()); // d
102 transcript.absorb_point(&proof.R)?;
103 let e = transcript.get_challenge();
104
105 // check that: R + cm == h⋅r_u + <g, u>
106 let lhs = proof.R + cm.mul(e);
107 // use msm_unchecked because we already ensured at the if that lengths match
108 let rhs = params.h.mul(proof.r_u)
109 + C::msm_unchecked(¶ms.generators[..proof.u.len()], &proof.u);
110 if lhs != rhs {
111 return Err(Error::PedersenVerificationFail);
112 }
113 Ok(())
114 }
115}
116
117pub type CF<C> = <<C as CurveGroup>::BaseField as Field>::BasePrimeField;
118
119pub struct PedersenGadget<C, GC>
120where
121 C: CurveGroup,
122 GC: CurveVar<C, CF<C>>,
123{
124 _cf: PhantomData<CF<C>>,
125 _c: PhantomData<C>,
126 _gc: PhantomData<GC>,
127}
128
129impl<C, GC> PedersenGadget<C, GC>
130where
131 C: CurveGroup,
132 GC: CurveVar<C, CF<C>>,
133
134 <C as ark_ec::CurveGroup>::BaseField: ark_ff::PrimeField,
135 for<'a> &'a GC: GroupOpsBounds<'a, C, GC>,
136{
137 pub fn commit(
138 h: GC,
139 g: Vec<GC>,
140 v: Vec<Vec<Boolean<CF<C>>>>,
141 r: Vec<Boolean<CF<C>>>,
142 ) -> Result<GC, SynthesisError> {
143 let mut res = GC::zero();
144 res += h.scalar_mul_le(r.iter())?;
145 for (i, v_i) in v.iter().enumerate() {
146 res += g[i].scalar_mul_le(v_i.iter())?;
147 }
148 Ok(res)
149 }
150}
151
152#[cfg(test)]
153mod tests {
154 use ark_ff::{BigInteger, PrimeField};
155 use ark_pallas::{constraints::GVar, Fq, Fr, Projective};
156 use ark_r1cs_std::{alloc::AllocVar, bits::boolean::Boolean, eq::EqGadget};
157 use ark_relations::r1cs::ConstraintSystem;
158 use ark_std::UniformRand;
159
160 use super::*;
161 use crate::transcript::poseidon::{tests::poseidon_test_config, PoseidonTranscript};
162
163 #[test]
164 fn test_pedersen_vector() {
165 let mut rng = ark_std::test_rng();
166
167 const n: usize = 10;
168 // setup params
169 let params = Pedersen::<Projective>::new_params(&mut rng, n);
170 let poseidon_config = poseidon_test_config::<Fr>();
171
172 // init Prover's transcript
173 let mut transcript_p = PoseidonTranscript::<Projective>::new(&poseidon_config);
174 // init Verifier's transcript
175 let mut transcript_v = PoseidonTranscript::<Projective>::new(&poseidon_config);
176
177 let v: Vec<Fr> = std::iter::repeat_with(|| Fr::rand(&mut rng))
178 .take(n)
179 .collect();
180 let r: Fr = Fr::rand(&mut rng);
181 let cm = Pedersen::<Projective>::commit(¶ms, &v, &r).unwrap();
182 let proof = Pedersen::<Projective>::prove(¶ms, &mut transcript_p, &cm, &v, &r).unwrap();
183 Pedersen::<Projective>::verify(¶ms, &mut transcript_v, cm, proof).unwrap();
184 }
185
186 #[test]
187 fn test_pedersen_circuit() {
188 let mut rng = ark_std::test_rng();
189
190 const n: usize = 10;
191 // setup params
192 let params = Pedersen::<Projective>::new_params(&mut rng, n);
193
194 let v: Vec<Fr> = std::iter::repeat_with(|| Fr::rand(&mut rng))
195 .take(n)
196 .collect();
197 let r: Fr = Fr::rand(&mut rng);
198 let cm = Pedersen::<Projective>::commit(¶ms, &v, &r).unwrap();
199
200 // circuit
201 let cs = ConstraintSystem::<Fq>::new_ref();
202
203 let v_bits: Vec<Vec<bool>> = v.iter().map(|val| val.into_bigint().to_bits_le()).collect();
204 let r_bits: Vec<bool> = r.into_bigint().to_bits_le();
205
206 // prepare inputs
207 let vVar: Vec<Vec<Boolean<Fq>>> = v_bits
208 .iter()
209 .map(|val_bits| {
210 Vec::<Boolean<Fq>>::new_witness(cs.clone(), || Ok(val_bits.clone())).unwrap()
211 })
212 .collect();
213 let rVar = Vec::<Boolean<Fq>>::new_witness(cs.clone(), || Ok(r_bits)).unwrap();
214 let gVar = Vec::<GVar>::new_witness(cs.clone(), || Ok(params.generators)).unwrap();
215 let hVar = GVar::new_witness(cs.clone(), || Ok(params.h)).unwrap();
216 let expected_cmVar = GVar::new_witness(cs.clone(), || Ok(cm)).unwrap();
217
218 // use the gadget
219 let cmVar = PedersenGadget::<Projective, GVar>::commit(hVar, gVar, vVar, rVar).unwrap();
220 cmVar.enforce_equal(&expected_cmVar).unwrap();
221 }
222}