1use ark_ec::AffineRepr;
9use ark_r1cs_std::{
10 alloc::{AllocVar, AllocationMode},
11 boolean::Boolean,
12 convert::ToBitsGadget,
13 eq::EqGadget,
14 fields::fp::FpVar,
15 groups::CurveVar,
16};
17use ark_relations::gr1cs::{Namespace, SynthesisError};
18use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
19use ark_std::{UniformRand, borrow::Borrow, iter::repeat_with, marker::PhantomData, rand::RngCore};
20
21use super::{CommitmentDef, CommitmentDefGadget, CommitmentKey, CommitmentOps, Error};
22use crate::{
23 algebra::{field::emulated::EmulatedFieldVar, group::emulated::EmulatedAffineVar},
24 commitments::{CommitmentOpsGadget, GroupBasedCommitment},
25 traits::{CF1, CF2, SonobeCurve},
26 utils::null::Null,
27};
28
29#[derive(Clone, CanonicalSerialize, CanonicalDeserialize)]
32pub struct PedersenKey<C: SonobeCurve, const H: bool> {
33 g: Vec<C::Affine>,
34 h: C,
35}
36
37impl<C: SonobeCurve, const H: bool> CommitmentKey for PedersenKey<C, H> {
38 fn max_scalars_len(&self) -> usize {
39 self.g.len()
40 }
41}
42
43impl<C: SonobeCurve, const H: bool> PedersenKey<C, H> {
44 fn new(len: usize, mut rng: impl RngCore) -> Self {
45 let generators = repeat_with(|| C::rand(&mut rng))
46 .take(len.next_power_of_two())
47 .collect::<Vec<_>>();
48 Self {
49 g: C::normalize_batch(&generators),
50 h: if H { C::rand(&mut rng) } else { C::zero() },
51 }
52 }
53}
54
55impl<C: SonobeCurve> PedersenKey<C, true> {
56 fn commit(&self, v: &[C::ScalarField], r: &C::ScalarField) -> Result<C, Error> {
57 if self.g.len() < v.len() {
58 return Err(Error::MessageTooLong(self.g.len(), v.len()));
59 }
60 Ok(C::msm_unchecked(&self.g, v) + self.h.mul(r))
63 }
64}
65
66impl<C: SonobeCurve> PedersenKey<C, false> {
67 fn commit(&self, v: &[C::ScalarField]) -> Result<C, Error> {
68 if self.g.len() < v.len() {
69 return Err(Error::MessageTooLong(self.g.len(), v.len()));
70 }
71 Ok(C::msm_unchecked(&self.g, v))
74 }
75}
76
77pub struct PedersenKeyVar<C: SonobeCurve, const H: bool> {
80 g: Vec<C::Var>,
81 h: C::Var,
82}
83
84pub struct PedersenEmulatedKeyVar<C: SonobeCurve, const H: bool> {
87 #[allow(dead_code)]
88 g: Vec<EmulatedAffineVar<CF1<C>, C>>,
89 #[allow(dead_code)]
90 h: EmulatedAffineVar<CF1<C>, C>,
91}
92
93impl<C: SonobeCurve, const H: bool> AllocVar<PedersenKey<C, H>, C::BaseField>
94 for PedersenKeyVar<C, H>
95{
96 fn new_variable<T: Borrow<PedersenKey<C, H>>>(
97 cs: impl Into<Namespace<C::BaseField>>,
98 f: impl FnOnce() -> Result<T, SynthesisError>,
99 mode: AllocationMode,
100 ) -> Result<Self, SynthesisError> {
101 let cs = cs.into().cs();
102 let v = f()?;
103 let PedersenKey { g, h } = v.borrow();
104
105 Ok(Self {
106 g: AllocVar::new_variable(cs.clone(), || Ok(&g[..]), mode)?,
107 h: AllocVar::new_variable(cs.clone(), || Ok(*h), mode)?,
108 })
109 }
110}
111
112impl<C: SonobeCurve, const H: bool> AllocVar<PedersenKey<C, H>, CF1<C>>
113 for PedersenEmulatedKeyVar<C, H>
114{
115 fn new_variable<T: Borrow<PedersenKey<C, H>>>(
116 cs: impl Into<Namespace<CF1<C>>>,
117 f: impl FnOnce() -> Result<T, SynthesisError>,
118 mode: AllocationMode,
119 ) -> Result<Self, SynthesisError> {
120 let cs = cs.into().cs();
121 let v = f()?;
122 let PedersenKey { g, h } = v.borrow();
123
124 Ok(Self {
125 g: AllocVar::new_variable(
126 cs.clone(),
127 || Ok(g.iter().map(|i| i.into_group()).collect::<Vec<_>>()),
128 mode,
129 )?,
130 h: AllocVar::new_variable(cs.clone(), || Ok(*h), mode)?,
131 })
132 }
133}
134
135#[derive(Clone, Debug, PartialEq, Eq)]
138pub struct Pedersen<C: SonobeCurve, const H: bool> {
139 _c: PhantomData<C>,
140}
141
142impl<C: SonobeCurve> CommitmentDef for Pedersen<C, false> {
143 const IS_HIDING: bool = false;
144
145 type Key = PedersenKey<C, false>;
146 type Scalar = C::ScalarField;
147 type Commitment = C;
148 type Randomness = Null;
149}
150
151impl<C: SonobeCurve> CommitmentDef for Pedersen<C, true> {
152 const IS_HIDING: bool = true;
153
154 type Key = PedersenKey<C, true>;
155 type Scalar = C::ScalarField;
156 type Commitment = C;
157 type Randomness = C::ScalarField;
158}
159
160impl<C: SonobeCurve> GroupBasedCommitment for Pedersen<C, false> {
161 type Gadget1 = PedersenGadget<C, false>;
162 type Gadget2 = PedersenEmulatedGadget<C, false>;
163}
164
165impl<C: SonobeCurve> GroupBasedCommitment for Pedersen<C, true> {
166 type Gadget1 = PedersenGadget<C, true>;
167 type Gadget2 = PedersenEmulatedGadget<C, true>;
168}
169
170impl<C: SonobeCurve> CommitmentOps for Pedersen<C, false> {
171 fn generate_key(len: usize, rng: impl RngCore) -> Result<PedersenKey<C, false>, Error> {
172 Ok(PedersenKey::new(len, rng))
173 }
174
175 fn commit(
176 ck: &PedersenKey<C, false>,
177 v: &[CF1<C>],
178 _rng: impl RngCore,
179 ) -> Result<(C, Null), Error> {
180 Ok((ck.commit(v)?, Null))
181 }
182
183 fn open(ck: &PedersenKey<C, false>, v: &[CF1<C>], _r: &Null, cm: &C) -> Result<(), Error> {
184 (&ck.commit(v)? == cm)
185 .then_some(())
186 .ok_or(Error::CommitmentVerificationFail)
187 }
188}
189
190impl<C: SonobeCurve> CommitmentOps for Pedersen<C, true> {
191 fn generate_key(len: usize, rng: impl RngCore) -> Result<PedersenKey<C, true>, Error> {
192 Ok(PedersenKey::new(len, rng))
193 }
194
195 fn commit(
196 ck: &PedersenKey<C, true>,
197 v: &[CF1<C>],
198 mut rng: impl RngCore,
199 ) -> Result<(C, CF1<C>), Error> {
200 let r = C::ScalarField::rand(&mut rng);
201 Ok((ck.commit(v, &r)?, r))
202 }
203
204 fn open(ck: &PedersenKey<C, true>, v: &[CF1<C>], r: &CF1<C>, cm: &C) -> Result<(), Error> {
205 (&(ck.commit(v, r)?) == cm)
206 .then_some(())
207 .ok_or(Error::CommitmentVerificationFail)
208 }
209}
210
211#[derive(Clone)]
216pub struct PedersenGadget<C: SonobeCurve, const H: bool> {
217 _c: PhantomData<C>,
218}
219
220impl<C: SonobeCurve, const H: bool> PedersenGadget<C, H> {
221 fn msm(g: &[C::Var], v: &[Vec<Boolean<CF2<C>>>]) -> Result<C::Var, SynthesisError> {
224 let mut res = C::Var::zero();
225 for (g_i, v_i) in g.iter().zip(v) {
226 res += g_i.scalar_mul_le(v_i.to_bits_le()?.iter())?;
227 }
228 Ok(res)
229 }
230}
231
232impl<C: SonobeCurve> CommitmentOpsGadget for PedersenGadget<C, false> {
233 fn open(
234 ck: &PedersenKeyVar<C, false>,
235 v: &[EmulatedFieldVar<CF2<C>, CF1<C>>],
236 _r: &Null,
237 cm: &C::Var,
238 ) -> Result<(), SynthesisError> {
239 Self::msm(
240 &ck.g,
241 &v.iter()
242 .map(|i| i.to_bits_le())
243 .collect::<Result<Vec<_>, _>>()?,
244 )?
245 .enforce_equal(cm)
246 }
247}
248
249impl<C: SonobeCurve> CommitmentOpsGadget for PedersenGadget<C, true> {
250 fn open(
251 ck: &PedersenKeyVar<C, true>,
252 v: &[EmulatedFieldVar<CF2<C>, CF1<C>>],
253 r: &EmulatedFieldVar<CF2<C>, CF1<C>>,
254 cm: &C::Var,
255 ) -> Result<(), SynthesisError> {
256 let gv = Self::msm(
257 &ck.g,
258 &v.iter()
259 .map(|i| i.to_bits_le())
260 .collect::<Result<Vec<_>, _>>()?,
261 )?;
262 let hr = ck.h.scalar_mul_le(r.to_bits_le()?.iter())?;
263 (gv + hr).enforce_equal(cm)
264 }
265}
266
267#[derive(Clone, Debug, PartialEq, Eq)]
272pub struct PedersenEmulatedGadget<C: SonobeCurve, const H: bool> {
273 _c: PhantomData<C>,
274}
275
276impl<C: SonobeCurve> CommitmentDefGadget for PedersenGadget<C, false> {
277 type ConstraintField = CF2<C>;
278
279 type KeyVar = PedersenKeyVar<C, false>;
280
281 type ScalarVar = EmulatedFieldVar<CF2<C>, CF1<C>>;
282
283 type CommitmentVar = C::Var;
284
285 type RandomnessVar = Null;
286
287 type Widget = Pedersen<C, false>;
288}
289
290impl<C: SonobeCurve> CommitmentDefGadget for PedersenGadget<C, true> {
291 type ConstraintField = CF2<C>;
292
293 type KeyVar = PedersenKeyVar<C, true>;
294
295 type ScalarVar = EmulatedFieldVar<CF2<C>, CF1<C>>;
296
297 type CommitmentVar = C::Var;
298
299 type RandomnessVar = EmulatedFieldVar<CF2<C>, CF1<C>>;
300
301 type Widget = Pedersen<C, true>;
302}
303
304impl<C: SonobeCurve> CommitmentDefGadget for PedersenEmulatedGadget<C, false> {
305 type ConstraintField = CF1<C>;
306
307 type KeyVar = PedersenEmulatedKeyVar<C, false>;
308
309 type ScalarVar = FpVar<CF1<C>>;
310
311 type CommitmentVar = EmulatedAffineVar<CF1<C>, C>;
312
313 type RandomnessVar = Null;
314
315 type Widget = Pedersen<C, false>;
316}
317
318impl<C: SonobeCurve> CommitmentDefGadget for PedersenEmulatedGadget<C, true> {
319 type ConstraintField = CF1<C>;
320
321 type KeyVar = PedersenEmulatedKeyVar<C, true>;
322
323 type ScalarVar = FpVar<CF1<C>>;
324
325 type CommitmentVar = EmulatedAffineVar<CF1<C>, C>;
326
327 type RandomnessVar = FpVar<CF1<C>>;
328
329 type Widget = Pedersen<C, true>;
330}
331
332#[cfg(test)]
333mod tests {
334 use ark_bn254::G1Projective;
335 use ark_std::{
336 error::Error,
337 rand::{Rng, thread_rng},
338 };
339 #[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
340 use wasm_bindgen_test::wasm_bindgen_test as test;
341
342 use super::*;
343 use crate::commitments::tests::{
344 test_commitment_correctness, test_commitment_gadget_correctness,
345 };
346
347 #[test]
348 fn test_pedersen_commitment() -> Result<(), Box<dyn Error>> {
349 let mut rng = thread_rng();
350 for i in 0..10 {
351 let len = rng.gen_range((1 << i)..(1 << (i + 1)));
352 test_commitment_correctness::<Pedersen<G1Projective, false>>(&mut rng, len)?;
353 test_commitment_correctness::<Pedersen<G1Projective, true>>(&mut rng, len)?;
354 }
355 Ok(())
356 }
357
358 #[test]
359 fn test_pedersen_commitment_circuit() -> Result<(), Box<dyn Error>> {
360 let mut rng = thread_rng();
361 for i in 0..5 {
362 let len = rng.gen_range((1 << i)..(1 << (i + 1)));
363 test_commitment_gadget_correctness::<PedersenGadget<G1Projective, false>>(
364 &mut rng, len,
365 )?;
366 test_commitment_gadget_correctness::<PedersenGadget<G1Projective, true>>(
367 &mut rng, len,
368 )?;
369 }
370 Ok(())
371 }
372}