ark-r1cs-std/crypto-primitives/src/nizk/groth16/constraints.rs
crypto-primitives/src/nizk/groth16/constraints.rsRaw
1use crate::{
2 nizk::{groth16::Groth16, NIZKVerifierGadget},
3 Vec,
4};
5use algebra_core::{AffineCurve, PairingEngine, ToConstraintField};
6use r1cs_core::{ConstraintSynthesizer, Namespace, SynthesisError};
7use r1cs_std::prelude::*;
8
9use core::{borrow::Borrow, marker::PhantomData};
10use groth16::{PreparedVerifyingKey, Proof, VerifyingKey};
11
12#[derive(Derivative)]
13#[derivative(Clone(bound = "P::G1Var: Clone, P::G2Var: Clone"))]
14pub struct ProofVar<E: PairingEngine, P: PairingVar<E>> {
15 pub a: P::G1Var,
16 pub b: P::G2Var,
17 pub c: P::G1Var,
18}
19
20#[derive(Derivative)]
21#[derivative(
22 Clone(bound = "P::G1Var: Clone, P::GTVar: Clone, P::G1PreparedVar: Clone, \
23 P::G2PreparedVar: Clone, ")
24)]
25pub struct VerifyingKeyVar<E: PairingEngine, P: PairingVar<E>> {
26 pub alpha_g1: P::G1Var,
27 pub beta_g2: P::G2Var,
28 pub gamma_g2: P::G2Var,
29 pub delta_g2: P::G2Var,
30 pub gamma_abc_g1: Vec<P::G1Var>,
31}
32
33impl<E: PairingEngine, P: PairingVar<E>> VerifyingKeyVar<E, P> {
34 pub fn prepare(&self) -> Result<PreparedVerifyingKeyVar<E, P>, SynthesisError> {
35 let alpha_g1_pc = P::prepare_g1(&self.alpha_g1)?;
36 let beta_g2_pc = P::prepare_g2(&self.beta_g2)?;
37
38 let alpha_g1_beta_g2 = P::pairing(alpha_g1_pc, beta_g2_pc)?;
39 let gamma_g2_neg_pc = P::prepare_g2(&self.gamma_g2.negate()?)?;
40 let delta_g2_neg_pc = P::prepare_g2(&self.delta_g2.negate()?)?;
41
42 Ok(PreparedVerifyingKeyVar {
43 alpha_g1_beta_g2,
44 gamma_g2_neg_pc,
45 delta_g2_neg_pc,
46 gamma_abc_g1: self.gamma_abc_g1.clone(),
47 })
48 }
49}
50
51#[derive(Derivative)]
52#[derivative(
53 Clone(bound = "P::G1Var: Clone, P::GTVar: Clone, P::G1PreparedVar: Clone, \
54 P::G2PreparedVar: Clone, ")
55)]
56pub struct PreparedVerifyingKeyVar<E: PairingEngine, P: PairingVar<E>> {
57 pub alpha_g1_beta_g2: P::GTVar,
58 pub gamma_g2_neg_pc: P::G2PreparedVar,
59 pub delta_g2_neg_pc: P::G2PreparedVar,
60 pub gamma_abc_g1: Vec<P::G1Var>,
61}
62
63pub struct Groth16VerifierGadget<E, P>
64where
65 E: PairingEngine,
66
67 P: PairingVar<E>,
68{
69 _pairing_engine: PhantomData<E>,
70 _pairing_gadget: PhantomData<P>,
71}
72
73impl<E, P, C, V> NIZKVerifierGadget<Groth16<E, C, V>, E::Fq> for Groth16VerifierGadget<E, P>
74where
75 E: PairingEngine,
76 C: ConstraintSynthesizer<E::Fr>,
77 V: ToConstraintField<E::Fr>,
78 P: PairingVar<E>,
79{
80 type PreparedVerificationKeyVar = PreparedVerifyingKeyVar<E, P>;
81 type VerificationKeyVar = VerifyingKeyVar<E, P>;
82 type ProofVar = ProofVar<E, P>;
83
84 /// Allocates `N::Proof` in `cs` without performing
85 /// subgroup checks.
86 fn new_proof_unchecked<T: Borrow<Proof<E>>>(
87 cs: impl Into<Namespace<E::Fq>>,
88 f: impl FnOnce() -> Result<T, SynthesisError>,
89 mode: AllocationMode,
90 ) -> Result<Self::ProofVar, SynthesisError> {
91 let ns = cs.into();
92 let cs = ns.cs();
93 f().and_then(|proof| {
94 let proof = proof.borrow();
95 let a = CurveVar::new_variable_omit_prime_order_check(
96 cs.ns("Proof.a"),
97 || Ok(proof.a.into_projective()),
98 mode,
99 )?;
100 let b = CurveVar::new_variable_omit_prime_order_check(
101 cs.ns("Proof.b"),
102 || Ok(proof.b.into_projective()),
103 mode,
104 )?;
105 let c = CurveVar::new_variable_omit_prime_order_check(
106 cs.ns("Proof.c"),
107 || Ok(proof.c.into_projective()),
108 mode,
109 )?;
110 Ok(ProofVar { a, b, c })
111 })
112 }
113
114 /// Allocates `N::Proof` in `cs` without performing
115 /// subgroup checks.
116 fn new_verification_key_unchecked<T: Borrow<VerifyingKey<E>>>(
117 cs: impl Into<Namespace<E::Fq>>,
118 f: impl FnOnce() -> Result<T, SynthesisError>,
119 mode: AllocationMode,
120 ) -> Result<Self::VerificationKeyVar, SynthesisError> {
121 let ns = cs.into();
122 let cs = ns.cs();
123 f().and_then(|vk| {
124 let vk = vk.borrow();
125 let alpha_g1 = P::G1Var::new_variable_omit_prime_order_check(
126 cs.ns("alpha_g1"),
127 || Ok(vk.alpha_g1.into_projective()),
128 mode,
129 )?;
130 let beta_g2 = P::G2Var::new_variable_omit_prime_order_check(
131 cs.ns("beta_g2"),
132 || Ok(vk.beta_g2.into_projective()),
133 mode,
134 )?;
135 let gamma_g2 = P::G2Var::new_variable_omit_prime_order_check(
136 cs.ns("gamma_g2"),
137 || Ok(vk.gamma_g2.into_projective()),
138 mode,
139 )?;
140 let delta_g2 = P::G2Var::new_variable_omit_prime_order_check(
141 cs.ns("delta_g2"),
142 || Ok(vk.delta_g2.into_projective()),
143 mode,
144 )?;
145
146 let gamma_abc_g1 = vk
147 .gamma_abc_g1
148 .iter()
149 .map(|g| {
150 P::G1Var::new_variable_omit_prime_order_check(
151 cs.ns("g"),
152 || Ok(g.into_projective()),
153 mode,
154 )
155 })
156 .collect::<Result<Vec<_>, _>>()?;
157 Ok(VerifyingKeyVar {
158 alpha_g1,
159 beta_g2,
160 gamma_g2,
161 delta_g2,
162 gamma_abc_g1,
163 })
164 })
165 }
166
167 fn conditional_verify<'a, T: 'a + ToBitsGadget<E::Fq> + ?Sized>(
168 vk: &Self::VerificationKeyVar,
169 input: impl Iterator<Item = &'a T>,
170 proof: &Self::ProofVar,
171 condition: &Boolean<E::Fq>,
172 ) -> Result<(), SynthesisError> {
173 let pvk = vk.prepare()?;
174 <Self as NIZKVerifierGadget<Groth16<E, C, V>, E::Fq>>::conditional_verify_prepared(
175 &pvk, input, proof, condition,
176 )
177 }
178
179 fn conditional_verify_prepared<'a, T: 'a + ToBitsGadget<E::Fq> + ?Sized>(
180 pvk: &Self::PreparedVerificationKeyVar,
181 mut public_inputs: impl Iterator<Item = &'a T>,
182 proof: &Self::ProofVar,
183 condition: &Boolean<E::Fq>,
184 ) -> Result<(), SynthesisError> {
185 let pvk = pvk.clone();
186
187 let g_ic = {
188 let mut g_ic: P::G1Var = pvk.gamma_abc_g1[0].clone();
189 let mut input_len = 1;
190 for (input, b) in public_inputs.by_ref().zip(pvk.gamma_abc_g1.iter().skip(1)) {
191 let encoded_input_i: P::G1Var = b.mul_bits(input.to_bits()?.iter())?;
192 g_ic += encoded_input_i;
193 input_len += 1;
194 }
195 // Check that the input and the query in the verification are of the
196 // same length.
197 assert!(input_len == pvk.gamma_abc_g1.len() && public_inputs.next().is_none());
198 g_ic
199 };
200
201 let test_exp = {
202 let proof_a_prep = P::prepare_g1(&proof.a)?;
203 let proof_b_prep = P::prepare_g2(&proof.b)?;
204 let proof_c_prep = P::prepare_g1(&proof.c)?;
205
206 let g_ic_prep = P::prepare_g1(&g_ic)?;
207
208 P::miller_loop(
209 &[proof_a_prep, g_ic_prep, proof_c_prep],
210 &[
211 proof_b_prep,
212 pvk.gamma_g2_neg_pc.clone(),
213 pvk.delta_g2_neg_pc.clone(),
214 ],
215 )?
216 };
217
218 let test = P::final_exponentiation(&test_exp).unwrap();
219
220 test.conditional_enforce_equal(&pvk.alpha_g1_beta_g2, condition)?;
221 Ok(())
222 }
223}
224
225impl<E, P> AllocVar<PreparedVerifyingKey<E>, E::Fq> for PreparedVerifyingKeyVar<E, P>
226where
227 E: PairingEngine,
228 P: PairingVar<E>,
229{
230 fn new_variable<T: Borrow<PreparedVerifyingKey<E>>>(
231 cs: impl Into<Namespace<E::Fq>>,
232 f: impl FnOnce() -> Result<T, SynthesisError>,
233 mode: AllocationMode,
234 ) -> Result<Self, SynthesisError> {
235 let ns = cs.into();
236 let cs = ns.cs();
237
238 f().and_then(|pvk| {
239 let pvk = pvk.borrow();
240 let alpha_g1_beta_g2 = P::GTVar::new_variable(
241 cs.ns("alpha_g1_beta_g2"),
242 || Ok(pvk.alpha_g1_beta_g2),
243 mode,
244 )?;
245
246 let gamma_g2_neg_pc = P::G2PreparedVar::new_variable(
247 cs.ns("gamma_g2_neg_pc"),
248 || Ok(pvk.gamma_g2_neg_pc.clone()),
249 mode,
250 )?;
251
252 let delta_g2_neg_pc = P::G2PreparedVar::new_variable(
253 cs.ns("delta_g2_neg_pc"),
254 || Ok(pvk.delta_g2_neg_pc.clone()),
255 mode,
256 )?;
257
258 let gamma_abc_g1 =
259 Vec::new_variable(cs.ns("gamma_abc_g1"), || Ok(pvk.gamma_abc_g1.clone()), mode)?;
260
261 Ok(Self {
262 alpha_g1_beta_g2,
263 gamma_g2_neg_pc,
264 delta_g2_neg_pc,
265 gamma_abc_g1,
266 })
267 })
268 }
269}
270
271impl<E, P> AllocVar<VerifyingKey<E>, E::Fq> for VerifyingKeyVar<E, P>
272where
273 E: PairingEngine,
274
275 P: PairingVar<E>,
276{
277 fn new_variable<T: Borrow<VerifyingKey<E>>>(
278 cs: impl Into<Namespace<E::Fq>>,
279 f: impl FnOnce() -> Result<T, SynthesisError>,
280 mode: AllocationMode,
281 ) -> Result<Self, SynthesisError> {
282 let ns = cs.into();
283 let cs = ns.cs();
284
285 f().and_then(|vk| {
286 let VerifyingKey {
287 alpha_g1,
288 beta_g2,
289 gamma_g2,
290 delta_g2,
291 gamma_abc_g1,
292 } = vk.borrow().clone();
293 let alpha_g1 = P::G1Var::new_variable(cs.ns("alpha_g1"), || Ok(alpha_g1), mode)?;
294 let beta_g2 = P::G2Var::new_variable(cs.ns("beta_g2"), || Ok(beta_g2), mode)?;
295 let gamma_g2 = P::G2Var::new_variable(cs.ns("gamma_g2"), || Ok(gamma_g2), mode)?;
296 let delta_g2 = P::G2Var::new_variable(cs.ns("delta_g2"), || Ok(delta_g2), mode)?;
297
298 let gamma_abc_g1 = Vec::new_variable(cs.clone(), || Ok(gamma_abc_g1), mode)?;
299 Ok(Self {
300 alpha_g1,
301 beta_g2,
302 gamma_g2,
303 delta_g2,
304 gamma_abc_g1,
305 })
306 })
307 }
308}
309
310impl<E, P> AllocVar<Proof<E>, E::Fq> for ProofVar<E, P>
311where
312 E: PairingEngine,
313 P: PairingVar<E>,
314{
315 fn new_variable<T: Borrow<Proof<E>>>(
316 cs: impl Into<Namespace<E::Fq>>,
317 f: impl FnOnce() -> Result<T, SynthesisError>,
318 mode: AllocationMode,
319 ) -> Result<Self, SynthesisError> {
320 let ns = cs.into();
321 let cs = ns.cs();
322
323 f().and_then(|proof| {
324 let Proof { a, b, c } = proof.borrow().clone();
325 let a = P::G1Var::new_variable(cs.ns("a"), || Ok(a), mode)?;
326 let b = P::G2Var::new_variable(cs.ns("b"), || Ok(b), mode)?;
327 let c = P::G1Var::new_variable(cs.ns("c"), || Ok(c), mode)?;
328 Ok(Self { a, b, c })
329 })
330 }
331}
332
333impl<E, P> ToBytesGadget<E::Fq> for VerifyingKeyVar<E, P>
334where
335 E: PairingEngine,
336 P: PairingVar<E>,
337{
338 #[inline]
339 fn to_bytes(&self) -> Result<Vec<UInt8<E::Fq>>, SynthesisError> {
340 let mut bytes = Vec::new();
341 bytes.extend_from_slice(&self.alpha_g1.to_bytes()?);
342 bytes.extend_from_slice(&self.beta_g2.to_bytes()?);
343 bytes.extend_from_slice(&self.gamma_g2.to_bytes()?);
344 bytes.extend_from_slice(&self.delta_g2.to_bytes()?);
345 for g in &self.gamma_abc_g1 {
346 bytes.extend_from_slice(&g.to_bytes()?);
347 }
348 Ok(bytes)
349 }
350}
351
352#[cfg(test)]
353mod test {
354 use groth16::*;
355 use r1cs_core::{
356 lc, ConstraintSynthesizer, ConstraintSystem, ConstraintSystemRef, SynthesisError,
357 };
358
359 use super::*;
360 use algebra::{
361 bls12_377::{Bls12_377, Fq, Fr},
362 test_rng, BitIterator, Field, PrimeField,
363 };
364 use r1cs_std::{bls12_377::PairingVar as Bls12_377PairingVar, boolean::Boolean, Assignment};
365 use rand::Rng;
366
367 type TestProofSystem = Groth16<Bls12_377, Bench<Fr>, Fr>;
368 type TestVerifierGadget = Groth16VerifierGadget<Bls12_377, Bls12_377PairingVar>;
369 type TestProofVar = ProofVar<Bls12_377, Bls12_377PairingVar>;
370 type TestVkVar = VerifyingKeyVar<Bls12_377, Bls12_377PairingVar>;
371
372 struct Bench<F: Field> {
373 inputs: Vec<Option<F>>,
374 num_constraints: usize,
375 }
376
377 impl<F: Field> ConstraintSynthesizer<F> for Bench<F> {
378 fn generate_constraints(self, cs: ConstraintSystemRef<F>) -> Result<(), SynthesisError> {
379 assert!(self.inputs.len() >= 2);
380 assert!(self.num_constraints >= self.inputs.len());
381
382 let mut variables: Vec<_> = Vec::with_capacity(self.inputs.len());
383 for input in self.inputs {
384 let input_var = cs.new_input_variable(|| input.get())?;
385 variables.push((input, input_var));
386 }
387
388 for i in 0..self.num_constraints {
389 let new_entry = {
390 let (input_1_val, input_1_var) = variables[i];
391 let (input_2_val, input_2_var) = variables[i + 1];
392 let result_val = input_1_val
393 .and_then(|input_1| input_2_val.map(|input_2| input_1 * &input_2));
394 let result_var = cs.new_witness_variable(|| {
395 result_val.ok_or(SynthesisError::AssignmentMissing)
396 })?;
397 cs.enforce_named_constraint(
398 format!("Enforce constraint {}", i),
399 lc!() + input_1_var,
400 lc!() + input_2_var,
401 lc!() + result_var,
402 )
403 .unwrap();
404 (result_val, result_var)
405 };
406 variables.push(new_entry);
407 }
408 Ok(())
409 }
410 }
411
412 #[test]
413 fn groth16_verifier_test() {
414 let num_inputs = 100;
415 let num_constraints = num_inputs;
416 let rng = &mut test_rng();
417 let mut inputs: Vec<Option<Fr>> = Vec::with_capacity(num_inputs);
418 for _ in 0..num_inputs {
419 inputs.push(Some(rng.gen()));
420 }
421 let params = {
422 let c = Bench::<Fr> {
423 inputs: vec![None; num_inputs],
424 num_constraints,
425 };
426
427 generate_random_parameters(c, rng).unwrap()
428 };
429
430 {
431 let proof = {
432 // Create an instance of our circuit (with the
433 // witness)
434 let c = Bench {
435 inputs: inputs.clone(),
436 num_constraints,
437 };
438 // Create a groth16 proof with our parameters.
439 create_random_proof(c, ¶ms, rng).unwrap()
440 };
441
442 // assert!(!verify_proof(&pvk, &proof, &[a]).unwrap());
443 let cs = ConstraintSystem::<Fq>::new_ref();
444
445 let inputs: Vec<_> = inputs.into_iter().map(|input| input.unwrap()).collect();
446 let mut input_gadgets = Vec::new();
447
448 {
449 for (i, input) in inputs.into_iter().enumerate() {
450 let mut input_bits = BitIterator::new(input.into_repr()).collect::<Vec<_>>();
451 // Input must be in little-endian, but BitIterator outputs in big-endian.
452 input_bits.reverse();
453
454 let input_bits =
455 Vec::<Boolean<Fq>>::new_input(cs.ns(format!("Input {}", i)), || {
456 Ok(input_bits)
457 })
458 .unwrap();
459 input_gadgets.push(input_bits);
460 }
461 }
462
463 let vk_gadget = TestVkVar::new_input(cs.ns("Vk"), || Ok(¶ms.vk)).unwrap();
464 let proof_gadget =
465 TestProofVar::new_witness(cs.ns("Proof"), || Ok(proof.clone())).unwrap();
466 println!("Time to verify!\n\n\n\n");
467 <TestVerifierGadget as NIZKVerifierGadget<TestProofSystem, Fq>>::verify(
468 &vk_gadget,
469 input_gadgets.iter(),
470 &proof_gadget,
471 )
472 .unwrap();
473 if !cs.is_satisfied().unwrap() {
474 println!("=========================================================");
475 println!("Unsatisfied constraints:");
476 println!("{:?}", cs.which_is_unsatisfied().unwrap());
477 println!("=========================================================");
478 }
479
480 // cs.print_named_objects();
481 assert!(cs.is_satisfied().unwrap());
482 }
483 }
484}
485
486#[cfg(test)]
487mod test_recursive {
488 use groth16::*;
489 use r1cs_core::{
490 lc, ConstraintSynthesizer, ConstraintSystem, ConstraintSystemRef, SynthesisError,
491 };
492
493 use super::*;
494 use algebra::{
495 fields::{FftParameters, FpParameters},
496 mnt4_298::{Fq as MNT4Fq, FqParameters as MNT4FqParameters, Fr as MNT4Fr, MNT4_298},
497 mnt6_298::{Fq as MNT6Fq, FqParameters as MNT6FqParameters, Fr as MNT6Fr, MNT6_298},
498 test_rng, BigInteger, Field, PrimeField,
499 };
500 use r1cs_std::{
501 fields::fp::FpVar, mnt4_298::PairingVar as MNT4_298PairingVar,
502 mnt6_298::PairingVar as MNT6_298PairingVar, uint8::UInt8, Assignment,
503 };
504 use rand::Rng;
505
506 type TestProofSystem1 = Groth16<MNT6_298, Bench<MNT4Fq>, MNT6Fr>;
507 type TestVerifierGadget1 = Groth16VerifierGadget<MNT6_298, MNT6_298PairingVar>;
508 type TestProofVar1 = ProofVar<MNT6_298, MNT6_298PairingVar>;
509 type TestVkVar1 = VerifyingKeyVar<MNT6_298, MNT6_298PairingVar>;
510
511 type TestProofSystem2 = Groth16<MNT4_298, Wrapper, MNT4Fr>;
512 type TestVerifierGadget2 = Groth16VerifierGadget<MNT4_298, MNT4_298PairingVar>;
513 type TestProofVar2 = ProofVar<MNT4_298, MNT4_298PairingVar>;
514 type TestVkVar2 = VerifyingKeyVar<MNT4_298, MNT4_298PairingVar>;
515
516 #[derive(Clone)]
517 struct Bench<F: Field> {
518 inputs: Vec<Option<F>>,
519 num_constraints: usize,
520 }
521
522 impl<F: Field> ConstraintSynthesizer<F> for Bench<F> {
523 fn generate_constraints(self, cs: ConstraintSystemRef<F>) -> Result<(), SynthesisError> {
524 assert!(self.inputs.len() >= 2);
525 assert!(self.num_constraints >= self.inputs.len());
526
527 let mut variables: Vec<_> = Vec::with_capacity(self.inputs.len());
528 for input in self.inputs {
529 let input_var = cs.new_input_variable(|| input.get())?;
530 variables.push((input, input_var));
531 }
532
533 for i in 0..self.num_constraints {
534 let new_entry = {
535 let (input_1_val, input_1_var) = variables[i];
536 let (input_2_val, input_2_var) = variables[i + 1];
537 let result_val = input_1_val
538 .and_then(|input_1| input_2_val.map(|input_2| input_1 * &input_2));
539 let result_var = cs.new_witness_variable(|| {
540 result_val.ok_or(SynthesisError::AssignmentMissing)
541 })?;
542 cs.enforce_named_constraint(
543 format!("Enforce constraint {}", i),
544 lc!() + input_1_var,
545 lc!() + input_2_var,
546 lc!() + result_var,
547 )
548 .unwrap();
549 (result_val, result_var)
550 };
551 variables.push(new_entry);
552 }
553 Ok(())
554 }
555 }
556
557 struct Wrapper {
558 inputs: Vec<Option<MNT4Fq>>,
559 params: Parameters<MNT6_298>,
560 proof: Proof<MNT6_298>,
561 }
562
563 impl ConstraintSynthesizer<MNT6Fq> for Wrapper {
564 fn generate_constraints(
565 self,
566 cs: ConstraintSystemRef<MNT6Fq>,
567 ) -> Result<(), SynthesisError> {
568 let params = self.params;
569 let proof = self.proof;
570 let inputs: Vec<_> = self
571 .inputs
572 .into_iter()
573 .map(|input| input.unwrap())
574 .collect();
575 let input_gadgets;
576
577 {
578 // Chain all input values in one large byte array.
579 let input_bytes = inputs
580 .clone()
581 .into_iter()
582 .flat_map(|input| {
583 input
584 .into_repr()
585 .as_ref()
586 .iter()
587 .flat_map(|l| l.to_le_bytes().to_vec())
588 .collect::<Vec<_>>()
589 })
590 .collect::<Vec<_>>();
591
592 // Allocate this byte array as input packed into field elements.
593 let input_bytes = UInt8::new_input_vec(cs.ns("Input"), &input_bytes[..])?;
594 // 40 byte
595 let element_size = <MNT4FqParameters as FftParameters>::BigInt::NUM_LIMBS * 8;
596 input_gadgets = input_bytes
597 .chunks(element_size)
598 .map(|chunk| {
599 chunk
600 .iter()
601 .flat_map(|byte| byte.into_bits_le())
602 .collect::<Vec<_>>()
603 })
604 .collect::<Vec<_>>();
605 }
606
607 let vk_gadget = TestVkVar1::new_witness(cs.ns("Vk"), || Ok(¶ms.vk))?;
608 let proof_gadget =
609 TestProofVar1::new_witness(cs.ns("Proof"), || Ok(proof.clone())).unwrap();
610 <TestVerifierGadget1 as NIZKVerifierGadget<TestProofSystem1, MNT6Fq>>::verify(
611 &vk_gadget,
612 input_gadgets.iter(),
613 &proof_gadget,
614 )?;
615 Ok(())
616 }
617 }
618
619 #[test]
620 fn groth16_recursive_verifier_test() {
621 let num_inputs = 5;
622 let num_constraints = num_inputs;
623 let rng = &mut test_rng();
624 let mut inputs: Vec<Option<MNT4Fq>> = Vec::with_capacity(num_inputs);
625 for _ in 0..num_inputs {
626 inputs.push(Some(rng.gen()));
627 }
628
629 // Generate inner params and proof.
630 let inner_params = {
631 let c = Bench::<MNT4Fq> {
632 inputs: vec![None; num_inputs],
633 num_constraints,
634 };
635
636 generate_random_parameters(c, rng).unwrap()
637 };
638
639 let inner_proof = {
640 // Create an instance of our circuit (with the
641 // witness)
642 let c = Bench {
643 inputs: inputs.clone(),
644 num_constraints,
645 };
646 // Create a groth16 proof with our parameters.
647 create_random_proof(c, &inner_params, rng).unwrap()
648 };
649
650 // Generate outer params and proof.
651 let params = {
652 let c = Wrapper {
653 inputs: inputs.clone(),
654 params: inner_params.clone(),
655 proof: inner_proof.clone(),
656 };
657
658 generate_random_parameters(c, rng).unwrap()
659 };
660
661 {
662 let proof = {
663 // Create an instance of our circuit (with the
664 // witness)
665 let c = Wrapper {
666 inputs: inputs.clone(),
667 params: inner_params.clone(),
668 proof: inner_proof.clone(),
669 };
670 // Create a groth16 proof with our parameters.
671 create_random_proof(c, ¶ms, rng).unwrap()
672 };
673
674 let cs = ConstraintSystem::<MNT4Fq>::new_ref();
675
676 let inputs: Vec<_> = inputs.into_iter().map(|input| input.unwrap()).collect();
677 let mut input_gadgets = Vec::new();
678
679 {
680 let bigint_size = <MNT4FqParameters as FftParameters>::BigInt::NUM_LIMBS * 64;
681 let mut input_bits = Vec::new();
682 for (i, input) in inputs.into_iter().enumerate() {
683 let input_gadget =
684 FpVar::new_input(cs.ns(format!("Input {}", i)), || Ok(input)).unwrap();
685 let mut fp_bits = input_gadget.to_bits().unwrap();
686
687 // FpVar::to_bits outputs a big-endian binary representation of
688 // fe_gadget's value, so we have to reverse it to get the little-endian
689 // form.
690 fp_bits.reverse();
691
692 // Use 320 bits per element.
693 for _ in fp_bits.len()..bigint_size {
694 fp_bits.push(Boolean::constant(false));
695 }
696 input_bits.extend_from_slice(&fp_bits);
697 }
698
699 // Pack input bits into field elements of the underlying circuit.
700 let max_size = 8 * (<MNT6FqParameters as FpParameters>::CAPACITY / 8) as usize;
701 let max_size = max_size as usize;
702 let bigint_size = <MNT6FqParameters as FftParameters>::BigInt::NUM_LIMBS * 64;
703 for chunk in input_bits.chunks(max_size) {
704 let mut chunk = chunk.to_vec();
705 let len = chunk.len();
706 for _ in len..bigint_size {
707 chunk.push(Boolean::constant(false));
708 }
709 input_gadgets.push(chunk);
710 }
711 // assert!(!verify_proof(&pvk, &proof, &[a]).unwrap());
712 }
713
714 let vk_gadget = TestVkVar2::new_input(cs.ns("Vk"), || Ok(¶ms.vk)).unwrap();
715 let proof_gadget =
716 TestProofVar2::new_witness(cs.ns("Proof"), || Ok(proof.clone())).unwrap();
717 println!("Time to verify!\n\n\n\n");
718 <TestVerifierGadget2 as NIZKVerifierGadget<TestProofSystem2, MNT4Fq>>::verify(
719 &vk_gadget,
720 input_gadgets.iter(),
721 &proof_gadget,
722 )
723 .unwrap();
724 if !cs.is_satisfied().unwrap() {
725 println!("=========================================================");
726 println!("Unsatisfied constraints:");
727 println!("{:?}", cs.which_is_unsatisfied().unwrap());
728 println!("=========================================================");
729 }
730
731 // cs.print_named_objects();
732 assert!(cs.is_satisfied().unwrap());
733 }
734 }
735}