ark-ec-blind-signatures/src/mala_nezhadansari/constraints.rs
src/mala_nezhadansari/constraints.rsRaw
1use crate::mala_nezhadansari::{ConstraintF, Parameters, PublicKey, Signature};
2
3use ark_ec::ProjectiveCurve;
4use ark_ed_on_bn254::{constraints::EdwardsVar, EdwardsParameters, FqParameters};
5use ark_ff::{fields::Fp256, to_bytes, PrimeField};
6use ark_r1cs_std::{
7 alloc::{AllocVar, AllocationMode},
8 bits::uint8::UInt8,
9 boolean::Boolean,
10 eq::EqGadget,
11 fields::fp::FpVar,
12 groups::GroupOpsBounds,
13 prelude::CurveVar,
14 ToBitsGadget,
15};
16use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystemRef, Namespace, SynthesisError};
17use ark_std::ops::Mul;
18
19use core::{borrow::Borrow, marker::PhantomData};
20use derivative::Derivative;
21
22// hash
23use arkworks_native_gadgets::poseidon as poseidon_native;
24// use arkworks_r1cs_gadgets::poseidon;
25use arkworks_r1cs_gadgets::poseidon::{FieldHasherGadget, PoseidonGadget};
26
27#[derive(Derivative)]
28#[derivative(
29 Debug(bound = "C: ProjectiveCurve, GC: CurveVar<C, ConstraintF<C>>"),
30 Clone(bound = "C: ProjectiveCurve, GC: CurveVar<C, ConstraintF<C>>")
31)]
32pub struct PublicKeyVar<C: ProjectiveCurve, GC: CurveVar<C, ConstraintF<C>>>
33where
34 for<'a> &'a GC: GroupOpsBounds<'a, C, GC>,
35{
36 pub pub_key: GC,
37 #[doc(hidden)]
38 _group: PhantomData<*const C>,
39}
40
41impl<C, GC> AllocVar<PublicKey<C>, ConstraintF<C>> for PublicKeyVar<C, GC>
42where
43 C: ProjectiveCurve,
44 GC: CurveVar<C, ConstraintF<C>>,
45 for<'a> &'a GC: GroupOpsBounds<'a, C, GC>,
46{
47 fn new_variable<T: Borrow<PublicKey<C>>>(
48 cs: impl Into<Namespace<ConstraintF<C>>>,
49 f: impl FnOnce() -> Result<T, SynthesisError>,
50 mode: AllocationMode,
51 ) -> Result<Self, SynthesisError> {
52 let pub_key = GC::new_variable(cs, f, mode)?;
53 Ok(Self {
54 pub_key,
55 _group: PhantomData,
56 })
57 }
58}
59
60#[derive(Clone, Debug)]
61pub struct Msg<const MSG_LEN: usize, C: ProjectiveCurve>(pub [ConstraintF<C>; MSG_LEN]);
62
63#[derive(Derivative)]
64#[derivative(
65 Debug(bound = "C: ProjectiveCurve, GC: CurveVar<C, ConstraintF<C>>"),
66 Clone(bound = "C: ProjectiveCurve, GC: CurveVar<C, ConstraintF<C>>")
67)]
68pub struct MsgVar<const MSG_LEN: usize, C: ProjectiveCurve, GC: CurveVar<C, ConstraintF<C>>>
69where
70 for<'a> &'a GC: GroupOpsBounds<'a, C, GC>,
71{
72 m: [FpVar<ConstraintF<C>>; MSG_LEN],
73 _gc: PhantomData<GC>,
74}
75impl<const MSG_LEN: usize, C, GC> MsgVar<MSG_LEN, C, GC>
76where
77 C: ProjectiveCurve,
78 GC: CurveVar<C, ConstraintF<C>>,
79 for<'a> &'a GC: GroupOpsBounds<'a, C, GC>,
80{
81 pub fn new(m: [FpVar<ConstraintF<C>>; MSG_LEN]) -> Self {
82 Self {
83 m,
84 _gc: PhantomData,
85 }
86 }
87}
88
89impl<const MSG_LEN: usize, C, GC> AllocVar<Msg<MSG_LEN, C>, ConstraintF<C>>
90 for MsgVar<MSG_LEN, C, GC>
91where
92 C: ProjectiveCurve,
93 GC: CurveVar<C, ConstraintF<C>>,
94 for<'a> &'a GC: GroupOpsBounds<'a, C, GC>,
95{
96 fn new_variable<T: Borrow<Msg<MSG_LEN, C>>>(
97 cs: impl Into<Namespace<ConstraintF<C>>>,
98 f: impl FnOnce() -> Result<T, SynthesisError>,
99 mode: AllocationMode,
100 ) -> Result<Self, SynthesisError> {
101 f().and_then(|m| {
102 let m = m.borrow();
103 let cs = cs.into();
104 let msg_vec: Vec<FpVar<ConstraintF<C>>> =
105 Vec::new_variable(cs, || Ok(m.clone().0), mode)?;
106 let m: [FpVar<ConstraintF<C>>; MSG_LEN] =
107 msg_vec
108 .try_into()
109 .unwrap_or_else(|v: Vec<FpVar<ConstraintF<C>>>| {
110 // WIP
111 panic!(
112 "Expected Vec of length: {}, actual length: {}",
113 MSG_LEN,
114 v.len()
115 )
116 });
117 Ok(Self {
118 m,
119 _gc: PhantomData,
120 })
121 })
122 }
123}
124
125#[derive(Derivative)]
126#[derivative(
127 Debug(bound = "C: ProjectiveCurve, GC: CurveVar<C, ConstraintF<C>>"),
128 Clone(bound = "C: ProjectiveCurve, GC: CurveVar<C, ConstraintF<C>>")
129)]
130pub struct SignatureVar<C: ProjectiveCurve, GC: CurveVar<C, ConstraintF<C>>>
131where
132 for<'a> &'a GC: GroupOpsBounds<'a, C, GC>,
133{
134 s: Vec<UInt8<ConstraintF<C>>>,
135 r: GC,
136 _curve: PhantomData<C>,
137}
138
139impl<C, GC> AllocVar<Signature<C>, ConstraintF<C>> for SignatureVar<C, GC>
140where
141 C: ProjectiveCurve,
142 GC: CurveVar<C, ConstraintF<C>>,
143 for<'a> &'a GC: GroupOpsBounds<'a, C, GC>,
144{
145 fn new_variable<T: Borrow<Signature<C>>>(
146 cs: impl Into<Namespace<ConstraintF<C>>>,
147 f: impl FnOnce() -> Result<T, SynthesisError>,
148 mode: AllocationMode,
149 ) -> Result<Self, SynthesisError> {
150 f().and_then(|val| {
151 let cs = cs.into();
152 // let s = val.borrow().s;
153 let mut s = Vec::<UInt8<ConstraintF<C>>>::new();
154 let s_bytes = to_bytes![val.borrow().s].unwrap();
155 #[allow(clippy::needless_range_loop)]
156 for i in 0..s_bytes.len() {
157 s.push(UInt8::<ConstraintF<C>>::new_variable(
158 cs.clone(),
159 || Ok(s_bytes[i]),
160 mode,
161 )?);
162 }
163
164 let r = GC::new_variable(cs, || Ok(val.borrow().r), mode)?;
165
166 Ok(Self {
167 s,
168 r,
169 _curve: PhantomData,
170 })
171 })
172 }
173}
174
175#[derive(Clone)]
176pub struct ParametersVar<C: ProjectiveCurve, GC: CurveVar<C, ConstraintF<C>>>
177where
178 for<'a> &'a GC: GroupOpsBounds<'a, C, GC>,
179{
180 generator: GC,
181 _curve: PhantomData<C>,
182}
183
184impl<C, GC> AllocVar<Parameters<C>, ConstraintF<C>> for ParametersVar<C, GC>
185where
186 C: ProjectiveCurve,
187 GC: CurveVar<C, ConstraintF<C>>,
188 for<'a> &'a GC: GroupOpsBounds<'a, C, GC>,
189{
190 fn new_variable<T: Borrow<Parameters<C>>>(
191 cs: impl Into<Namespace<ConstraintF<C>>>,
192 f: impl FnOnce() -> Result<T, SynthesisError>,
193 mode: AllocationMode,
194 ) -> Result<Self, SynthesisError> {
195 f().and_then(|val| {
196 let cs = cs.into();
197 let generator = GC::new_variable(cs, || Ok(val.borrow().generator), mode)?;
198 Ok(Self {
199 generator,
200 _curve: PhantomData,
201 })
202 })
203 }
204}
205
206pub struct BlindSigVerifyGadget<
207 const MSG_LEN: usize,
208 C: ProjectiveCurve,
209 GC: CurveVar<C, ConstraintF<C>>,
210> where
211 for<'a> &'a GC: GroupOpsBounds<'a, C, GC>,
212{
213 _params: Parameters<C>, // TODO review if needed, maybe delete
214 _gc: PhantomData<GC>,
215}
216
217impl<const MSG_LEN: usize, C: ProjectiveCurve, GC: CurveVar<C, ConstraintF<C>>>
218 BlindSigVerifyGadget<MSG_LEN, C, GC>
219where
220 C: ProjectiveCurve,
221 GC: CurveVar<C, ConstraintF<C>>,
222 for<'a> &'a GC: GroupOpsBounds<'a, C, GC>,
223 ark_r1cs_std::groups::curves::twisted_edwards::AffineVar<
224 EdwardsParameters,
225 FpVar<Fp256<FqParameters>>,
226 >: From<GC>,
227 <C as ProjectiveCurve>::BaseField: PrimeField,
228 FpVar<<C as ProjectiveCurve>::BaseField>: Mul<FpVar<Fp256<FqParameters>>>,
229 FpVar<<C as ProjectiveCurve>::BaseField>: From<FpVar<Fp256<FqParameters>>>,
230{
231 pub fn verify(
232 parameters: &ParametersVar<C, GC>,
233 poseidon_hash: &PoseidonGadget<ConstraintF<C>>,
234 m: &MsgVar<MSG_LEN, C, GC>,
235 s: &SignatureVar<C, GC>,
236 q: &PublicKeyVar<C, GC>,
237 ) -> Result<Boolean<ConstraintF<C>>, SynthesisError> {
238 let sG = parameters
239 .generator
240 .scalar_mul_le(s.s.to_bits_le()?.iter())?;
241
242 // Note: in a circuit that aggregates multiple verifications, the hashing step could be
243 // done outside the signature verification, once for all 1 votes and once for all 0 votes,
244 // saving lots of constraints
245 let hm = poseidon_hash.hash(&m.m)?;
246 let r = EdwardsVar::from(s.r.clone()); // WIP
247 let rx_fpvar: FpVar<ConstraintF<C>> = r.x.into();
248
249 // G * s == R + Q * (R.x * H(m))
250 let Q_rx_hm_0 = q.pub_key.scalar_mul_le(rx_fpvar.to_bits_le()?.iter())?;
251 let Q_rx_hm = Q_rx_hm_0.scalar_mul_le(hm.to_bits_le()?.iter())?;
252 let RHS = s.r.clone() + Q_rx_hm;
253
254 sG.is_eq(&RHS)
255 }
256}
257
258pub struct BlindSigBatchVerifyGadget<
259 const NUM_SIGS: usize,
260 const MSG_LEN: usize,
261 C: ProjectiveCurve,
262 GC: CurveVar<C, ConstraintF<C>>,
263> where
264 for<'a> &'a GC: GroupOpsBounds<'a, C, GC>,
265{
266 _params: Parameters<C>, // TODO review if needed, maybe delete
267 _gc: PhantomData<GC>,
268}
269
270impl<
271 const NUM_SIGS: usize,
272 const MSG_LEN: usize,
273 C: ProjectiveCurve,
274 GC: CurveVar<C, ConstraintF<C>>,
275 > BlindSigBatchVerifyGadget<NUM_SIGS, MSG_LEN, C, GC>
276where
277 C: ProjectiveCurve,
278 GC: CurveVar<C, ConstraintF<C>>,
279 for<'a> &'a GC: GroupOpsBounds<'a, C, GC>,
280 ark_r1cs_std::groups::curves::twisted_edwards::AffineVar<
281 EdwardsParameters,
282 FpVar<Fp256<FqParameters>>,
283 >: From<GC>,
284 <C as ProjectiveCurve>::BaseField: PrimeField,
285 FpVar<<C as ProjectiveCurve>::BaseField>: Mul<FpVar<Fp256<FqParameters>>>,
286 FpVar<<C as ProjectiveCurve>::BaseField>: From<FpVar<Fp256<FqParameters>>>,
287{
288 pub fn batch_verify(
289 parameters: &ParametersVar<C, GC>,
290 poseidon_hash: &PoseidonGadget<ConstraintF<C>>,
291 m: &MsgVar<MSG_LEN, C, GC>,
292 sigs: &[SignatureVar<C, GC>],
293 q: &PublicKeyVar<C, GC>,
294 ) -> Result<Boolean<ConstraintF<C>>, SynthesisError> {
295 // Note: in a circuit that aggregates multiple verifications, the hashing step could be
296 // done outside the signature verification, once for all 1 votes and once for all 0 votes,
297 // saving lots of constraints
298 let hm = poseidon_hash.hash(&m.m)?;
299
300 #[allow(clippy::needless_range_loop)]
301 for i in 0..NUM_SIGS {
302 let sG = parameters
303 .generator
304 .scalar_mul_le(sigs[i].s.to_bits_le()?.iter())?;
305
306 let r = EdwardsVar::from(sigs[i].r.clone()); // WIP
307 let rx_fpvar: FpVar<ConstraintF<C>> = r.x.into();
308
309 // G * s == R + Q * (R.x * H(m))
310 let Q_rx_hm_0 = q.pub_key.scalar_mul_le(rx_fpvar.to_bits_le()?.iter())?;
311 let Q_rx_hm = Q_rx_hm_0.scalar_mul_le(hm.to_bits_le()?.iter())?;
312 let RHS = sigs[i].r.clone() + Q_rx_hm;
313 sG.enforce_equal(&RHS)?;
314 }
315 Ok(Boolean::TRUE)
316 }
317}
318
319// example of circuit using BlindSigVerifyGadget to verify a single blind signature
320#[derive(Clone)]
321pub struct BlindSigVerifyCircuit<
322 const MSG_LEN: usize,
323 C: ProjectiveCurve,
324 GC: CurveVar<C, ConstraintF<C>>,
325> where
326 <C as ProjectiveCurve>::BaseField: PrimeField,
327{
328 _group: PhantomData<*const GC>,
329 pub params: Parameters<C>,
330 pub poseidon_hash_native: poseidon_native::Poseidon<ConstraintF<C>>,
331 pub signature: Option<Signature<C>>,
332 pub pub_key: Option<PublicKey<C>>,
333 pub message: Option<Msg<MSG_LEN, C>>,
334}
335
336impl<const MSG_LEN: usize, C: ProjectiveCurve, GC: CurveVar<C, ConstraintF<C>>>
337 ConstraintSynthesizer<ConstraintF<C>> for BlindSigVerifyCircuit<MSG_LEN, C, GC>
338where
339 C: ProjectiveCurve,
340 GC: CurveVar<C, ConstraintF<C>>,
341 for<'a> &'a GC: GroupOpsBounds<'a, C, GC>,
342 ark_r1cs_std::groups::curves::twisted_edwards::AffineVar<
343 EdwardsParameters,
344 FpVar<Fp256<FqParameters>>,
345 >: From<GC>,
346 <C as ProjectiveCurve>::BaseField: PrimeField,
347 FpVar<<C as ProjectiveCurve>::BaseField>: Mul<FpVar<Fp256<FqParameters>>>,
348 FpVar<<C as ProjectiveCurve>::BaseField>: From<FpVar<Fp256<FqParameters>>>,
349{
350 #[tracing::instrument(target = "r1cs", skip(self, cs))]
351 fn generate_constraints(
352 self,
353 cs: ConstraintSystemRef<ConstraintF<C>>,
354 ) -> Result<(), SynthesisError> {
355 let parameters =
356 ParametersVar::new_constant(ark_relations::ns!(cs, "parameters"), &self.params)?;
357
358 let pub_key =
359 PublicKeyVar::<C, GC>::new_input(ark_relations::ns!(cs, "public key"), || {
360 self.pub_key.ok_or(SynthesisError::AssignmentMissing)
361 })?;
362 let m = MsgVar::<MSG_LEN, C, GC>::new_input(ark_relations::ns!(cs, "message"), || {
363 self.message.ok_or(SynthesisError::AssignmentMissing)
364 })?;
365 let signature =
366 SignatureVar::<C, GC>::new_witness(ark_relations::ns!(cs, "signature"), || {
367 self.signature.ok_or(SynthesisError::AssignmentMissing)
368 })?;
369 #[allow(clippy::redundant_clone)]
370 let poseidon_hash = PoseidonGadget::<ConstraintF<C>>::from_native(
371 &mut cs.clone(),
372 self.poseidon_hash_native,
373 )
374 .unwrap();
375
376 let v = BlindSigVerifyGadget::<MSG_LEN, C, GC>::verify(
377 ¶meters,
378 &poseidon_hash,
379 &m,
380 &signature,
381 &pub_key,
382 )?;
383 v.enforce_equal(&Boolean::TRUE)
384 }
385}
386
387// example of circuit using BlindSigVerifyGadget to verify a batch of blind signatures
388#[derive(Clone)]
389pub struct BlindSigBatchVerifyCircuit<
390 const NUM_SIGS: usize,
391 const MSG_LEN: usize,
392 C: ProjectiveCurve,
393 GC: CurveVar<C, ConstraintF<C>>,
394> where
395 <C as ProjectiveCurve>::BaseField: PrimeField,
396{
397 _group: PhantomData<*const GC>,
398 pub params: Parameters<C>,
399 pub poseidon_hash_native: poseidon_native::Poseidon<ConstraintF<C>>,
400 pub signatures: Option<Vec<Signature<C>>>,
401 pub pub_key: Option<PublicKey<C>>,
402 pub message: Option<Msg<MSG_LEN, C>>,
403}
404
405impl<
406 const NUM_SIGS: usize,
407 const MSG_LEN: usize,
408 C: ProjectiveCurve,
409 GC: CurveVar<C, ConstraintF<C>>,
410 > ConstraintSynthesizer<ConstraintF<C>> for BlindSigBatchVerifyCircuit<NUM_SIGS, MSG_LEN, C, GC>
411where
412 C: ProjectiveCurve,
413 GC: CurveVar<C, ConstraintF<C>>,
414 for<'a> &'a GC: GroupOpsBounds<'a, C, GC>,
415 ark_r1cs_std::groups::curves::twisted_edwards::AffineVar<
416 EdwardsParameters,
417 FpVar<Fp256<FqParameters>>,
418 >: From<GC>,
419 <C as ProjectiveCurve>::BaseField: PrimeField,
420 FpVar<<C as ProjectiveCurve>::BaseField>: Mul<FpVar<Fp256<FqParameters>>>,
421 FpVar<<C as ProjectiveCurve>::BaseField>: From<FpVar<Fp256<FqParameters>>>,
422{
423 #[tracing::instrument(target = "r1cs", skip(self, cs))]
424 fn generate_constraints(
425 self,
426 cs: ConstraintSystemRef<ConstraintF<C>>,
427 ) -> Result<(), SynthesisError> {
428 let parameters =
429 ParametersVar::new_constant(ark_relations::ns!(cs, "parameters"), &self.params)?;
430
431 let pub_key =
432 PublicKeyVar::<C, GC>::new_input(ark_relations::ns!(cs, "public key"), || {
433 self.pub_key.ok_or(SynthesisError::AssignmentMissing)
434 })?;
435 let m = MsgVar::<MSG_LEN, C, GC>::new_input(ark_relations::ns!(cs, "message"), || {
436 self.message.ok_or(SynthesisError::AssignmentMissing)
437 })?;
438
439 let mut signatures: Vec<SignatureVar<C, GC>> = Vec::new();
440 for i in 0..NUM_SIGS {
441 let signature = self.signatures.as_ref().and_then(|s| s.get(i));
442
443 let signature =
444 SignatureVar::<C, GC>::new_witness(ark_relations::ns!(cs, "signature"), || {
445 signature.ok_or(SynthesisError::AssignmentMissing)
446 })?;
447 signatures.push(signature);
448 }
449
450 #[allow(clippy::redundant_clone)]
451 let poseidon_hash = PoseidonGadget::<ConstraintF<C>>::from_native(
452 &mut cs.clone(),
453 self.poseidon_hash_native,
454 )
455 .unwrap();
456
457 let v = BlindSigBatchVerifyGadget::<NUM_SIGS, MSG_LEN, C, GC>::batch_verify(
458 ¶meters,
459 &poseidon_hash,
460 &m,
461 &signatures,
462 &pub_key,
463 )?;
464 v.enforce_equal(&Boolean::TRUE)
465 }
466}
467
468#[cfg(test)]
469mod test {
470 use super::*;
471 use crate::mala_nezhadansari::{poseidon_setup_params, BlindSigScheme};
472 use ark_ed_on_bn254::constraints::EdwardsVar as BabyJubJubVar;
473 use ark_ed_on_bn254::EdwardsProjective as BabyJubJub;
474
475 use arkworks_native_gadgets::poseidon;
476 use arkworks_utils::Curve;
477
478 use ark_relations::r1cs::ConstraintSystem;
479
480 type Fq = <BabyJubJub as ProjectiveCurve>::BaseField;
481 // type Fr = <BabyJubJub as ProjectiveCurve>::ScalarField;
482 type S = BlindSigScheme<BabyJubJub>;
483
484 fn generate_single_sig_native_data(
485 poseidon_hash: &poseidon::Poseidon<Fq>,
486 ) -> (
487 Parameters<BabyJubJub>,
488 PublicKey<BabyJubJub>,
489 Msg<3, BabyJubJub>,
490 Signature<BabyJubJub>,
491 ) {
492 let mut rng = ark_std::test_rng();
493 let params = S::setup();
494 let (pk, sk) = S::keygen(¶ms, &mut rng);
495 let (k, signer_r) = S::new_request_params(¶ms, &mut rng);
496 let m = [Fq::from(1234), Fq::from(5689), Fq::from(3456)];
497 let (m_blinded, u) = S::blind(¶ms, &mut rng, &poseidon_hash, &m, signer_r).unwrap();
498 let s_blinded = S::blind_sign(sk, k, m_blinded);
499 let s = S::unblind(s_blinded, &u);
500 let verified = S::verify(¶ms, &poseidon_hash, &m, s.clone(), pk);
501 assert!(verified);
502 (params, pk, Msg(m), s)
503 }
504
505 fn generate_batch_sig_native_data(
506 poseidon_hash: &poseidon::Poseidon<Fq>,
507 n: usize,
508 ) -> (
509 Parameters<BabyJubJub>,
510 PublicKey<BabyJubJub>,
511 Msg<3, BabyJubJub>,
512 Vec<Signature<BabyJubJub>>,
513 ) {
514 let mut rng = ark_std::test_rng();
515 let params = S::setup();
516 let (pk, sk) = S::keygen(¶ms, &mut rng);
517 let m = [Fq::from(1234), Fq::from(5689), Fq::from(3456)];
518 let mut signatures: Vec<Signature<BabyJubJub>> = Vec::new();
519 for _ in 0..n {
520 let (k, signer_r) = S::new_request_params(¶ms, &mut rng);
521 let (m_blinded, u) = S::blind(¶ms, &mut rng, &poseidon_hash, &m, signer_r).unwrap();
522 let s_blinded = S::blind_sign(sk, k, m_blinded);
523 let s = S::unblind(s_blinded, &u);
524 let verified = S::verify(¶ms, &poseidon_hash, &m, s.clone(), pk);
525 assert!(verified);
526 signatures.push(s);
527 }
528 (params, pk, Msg(m), signatures)
529 }
530
531 #[test]
532 fn test_single_verify() {
533 let poseidon_params = poseidon_setup_params::<Fq>(Curve::Bn254, 5, 4);
534 let poseidon_hash = poseidon::Poseidon::new(poseidon_params);
535 const MSG_LEN: usize = 3;
536
537 // create signature using native-rust lib
538 let (params, pk, m, s) = generate_single_sig_native_data(&poseidon_hash);
539
540 // use the constraint system to verify the signature
541 type SG = BlindSigVerifyGadget<MSG_LEN, BabyJubJub, BabyJubJubVar>;
542 let cs = ConstraintSystem::<Fq>::new_ref();
543
544 let params_var =
545 ParametersVar::<BabyJubJub, BabyJubJubVar>::new_constant(cs.clone(), params).unwrap();
546 let signature_var =
547 SignatureVar::<BabyJubJub, BabyJubJubVar>::new_witness(cs.clone(), || Ok(&s)).unwrap();
548 let pk_var =
549 PublicKeyVar::<BabyJubJub, BabyJubJubVar>::new_witness(cs.clone(), || Ok(&pk)).unwrap();
550 let m_var = MsgVar::<MSG_LEN, BabyJubJub, BabyJubJubVar>::new_witness(cs.clone(), || Ok(m))
551 .unwrap();
552 let poseidon_hash_var =
553 PoseidonGadget::<Fq>::from_native(&mut cs.clone(), poseidon_hash).unwrap();
554
555 let valid_sig = SG::verify(
556 ¶ms_var,
557 &poseidon_hash_var,
558 &m_var,
559 &signature_var,
560 &pk_var,
561 )
562 .unwrap();
563 valid_sig.enforce_equal(&Boolean::<Fq>::TRUE).unwrap();
564 assert!(cs.is_satisfied().unwrap());
565 }
566
567 #[test]
568 fn test_single_verify_constraint_system() {
569 let poseidon_params = poseidon_setup_params::<Fq>(Curve::Bn254, 5, 4);
570 let poseidon_hash = poseidon::Poseidon::new(poseidon_params);
571 const MSG_LEN: usize = 3;
572
573 // create signature using native-rust lib
574 let (params, pk, m, s) = generate_single_sig_native_data(&poseidon_hash);
575
576 // use the constraint system to verify the signature
577 let circuit = BlindSigVerifyCircuit::<MSG_LEN, BabyJubJub, BabyJubJubVar> {
578 params,
579 poseidon_hash_native: poseidon_hash.clone(),
580 signature: Some(s),
581 pub_key: Some(pk),
582 message: Some(m),
583 _group: PhantomData,
584 };
585 let cs = ConstraintSystem::<Fq>::new_ref();
586 circuit.generate_constraints(cs.clone()).unwrap();
587 let is_satisfied = cs.is_satisfied().unwrap();
588 assert!(is_satisfied);
589 println!("num_constraints={:?}", cs.num_constraints());
590 }
591
592 #[test]
593 fn test_batch_verify_constraint_system() {
594 let poseidon_params = poseidon_setup_params::<Fq>(Curve::Bn254, 5, 4);
595 let poseidon_hash = poseidon::Poseidon::new(poseidon_params);
596 const MSG_LEN: usize = 3;
597
598 // create signatures using native-rust lib
599 const NUM_SIGS: usize = 5;
600 let (params, pk, m, sigs) = generate_batch_sig_native_data(&poseidon_hash, NUM_SIGS);
601
602 // use the constraint system to verify the batch of signatures
603 let circuit = BlindSigBatchVerifyCircuit::<NUM_SIGS, MSG_LEN, BabyJubJub, BabyJubJubVar> {
604 params,
605 poseidon_hash_native: poseidon_hash.clone(),
606 signatures: Some(sigs),
607 pub_key: Some(pk),
608 message: Some(m),
609 _group: PhantomData,
610 };
611 let cs = ConstraintSystem::<Fq>::new_ref();
612 circuit.generate_constraints(cs.clone()).unwrap();
613 let is_satisfied = cs.is_satisfied().unwrap();
614 assert!(is_satisfied);
615 println!("num_constraints={:?}", cs.num_constraints());
616 }
617}