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