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 IntoIterator<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 public_inputs: impl IntoIterator<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 let mut public_inputs = public_inputs.into_iter();
191 for (input, b) in public_inputs.by_ref().zip(pvk.gamma_abc_g1.iter().skip(1)) {
192 let encoded_input_i: P::G1Var = b.scalar_mul_le(input.to_bits_le()?.iter())?;
193 g_ic += encoded_input_i;
194 input_len += 1;
195 }
196 // Check that the input and the query in the verification are of the
197 // same length.
198 assert!(input_len == pvk.gamma_abc_g1.len() && public_inputs.next().is_none());
199 g_ic
200 };
201
202 let test_exp = {
203 let proof_a_prep = P::prepare_g1(&proof.a)?;
204 let proof_b_prep = P::prepare_g2(&proof.b)?;
205 let proof_c_prep = P::prepare_g1(&proof.c)?;
206
207 let g_ic_prep = P::prepare_g1(&g_ic)?;
208
209 P::miller_loop(
210 &[proof_a_prep, g_ic_prep, proof_c_prep],
211 &[
212 proof_b_prep,
213 pvk.gamma_g2_neg_pc.clone(),
214 pvk.delta_g2_neg_pc.clone(),
215 ],
216 )?
217 };
218
219 let test = P::final_exponentiation(&test_exp).unwrap();
220
221 test.conditional_enforce_equal(&pvk.alpha_g1_beta_g2, condition)?;
222 Ok(())
223 }
224}
225
226impl<E, P> AllocVar<PreparedVerifyingKey<E>, E::Fq> for PreparedVerifyingKeyVar<E, P>
227where
228 E: PairingEngine,
229 P: PairingVar<E>,
230{
231 fn new_variable<T: Borrow<PreparedVerifyingKey<E>>>(
232 cs: impl Into<Namespace<E::Fq>>,
233 f: impl FnOnce() -> Result<T, SynthesisError>,
234 mode: AllocationMode,
235 ) -> Result<Self, SynthesisError> {
236 let ns = cs.into();
237 let cs = ns.cs();
238
239 f().and_then(|pvk| {
240 let pvk = pvk.borrow();
241 let alpha_g1_beta_g2 = P::GTVar::new_variable(
242 cs.ns("alpha_g1_beta_g2"),
243 || Ok(pvk.alpha_g1_beta_g2),
244 mode,
245 )?;
246
247 let gamma_g2_neg_pc = P::G2PreparedVar::new_variable(
248 cs.ns("gamma_g2_neg_pc"),
249 || Ok(pvk.gamma_g2_neg_pc.clone()),
250 mode,
251 )?;
252
253 let delta_g2_neg_pc = P::G2PreparedVar::new_variable(
254 cs.ns("delta_g2_neg_pc"),
255 || Ok(pvk.delta_g2_neg_pc.clone()),
256 mode,
257 )?;
258
259 let gamma_abc_g1 =
260 Vec::new_variable(cs.ns("gamma_abc_g1"), || Ok(pvk.gamma_abc_g1.clone()), mode)?;
261
262 Ok(Self {
263 alpha_g1_beta_g2,
264 gamma_g2_neg_pc,
265 delta_g2_neg_pc,
266 gamma_abc_g1,
267 })
268 })
269 }
270}
271
272impl<E, P> AllocVar<VerifyingKey<E>, E::Fq> for VerifyingKeyVar<E, P>
273where
274 E: PairingEngine,
275
276 P: PairingVar<E>,
277{
278 fn new_variable<T: Borrow<VerifyingKey<E>>>(
279 cs: impl Into<Namespace<E::Fq>>,
280 f: impl FnOnce() -> Result<T, SynthesisError>,
281 mode: AllocationMode,
282 ) -> Result<Self, SynthesisError> {
283 let ns = cs.into();
284 let cs = ns.cs();
285
286 f().and_then(|vk| {
287 let VerifyingKey {
288 alpha_g1,
289 beta_g2,
290 gamma_g2,
291 delta_g2,
292 gamma_abc_g1,
293 } = vk.borrow().clone();
294 let alpha_g1 = P::G1Var::new_variable(cs.ns("alpha_g1"), || Ok(alpha_g1), mode)?;
295 let beta_g2 = P::G2Var::new_variable(cs.ns("beta_g2"), || Ok(beta_g2), mode)?;
296 let gamma_g2 = P::G2Var::new_variable(cs.ns("gamma_g2"), || Ok(gamma_g2), mode)?;
297 let delta_g2 = P::G2Var::new_variable(cs.ns("delta_g2"), || Ok(delta_g2), mode)?;
298
299 let gamma_abc_g1 = Vec::new_variable(cs.clone(), || Ok(gamma_abc_g1), mode)?;
300 Ok(Self {
301 alpha_g1,
302 beta_g2,
303 gamma_g2,
304 delta_g2,
305 gamma_abc_g1,
306 })
307 })
308 }
309}
310
311impl<E, P> AllocVar<Proof<E>, E::Fq> for ProofVar<E, P>
312where
313 E: PairingEngine,
314 P: PairingVar<E>,
315{
316 fn new_variable<T: Borrow<Proof<E>>>(
317 cs: impl Into<Namespace<E::Fq>>,
318 f: impl FnOnce() -> Result<T, SynthesisError>,
319 mode: AllocationMode,
320 ) -> Result<Self, SynthesisError> {
321 let ns = cs.into();
322 let cs = ns.cs();
323
324 f().and_then(|proof| {
325 let Proof { a, b, c } = proof.borrow().clone();
326 let a = P::G1Var::new_variable(cs.ns("a"), || Ok(a), mode)?;
327 let b = P::G2Var::new_variable(cs.ns("b"), || Ok(b), mode)?;
328 let c = P::G1Var::new_variable(cs.ns("c"), || Ok(c), mode)?;
329 Ok(Self { a, b, c })
330 })
331 }
332}
333
334impl<E, P> ToBytesGadget<E::Fq> for VerifyingKeyVar<E, P>
335where
336 E: PairingEngine,
337 P: PairingVar<E>,
338{
339 #[inline]
340 fn to_bytes(&self) -> Result<Vec<UInt8<E::Fq>>, SynthesisError> {
341 let mut bytes = Vec::new();
342 bytes.extend_from_slice(&self.alpha_g1.to_bytes()?);
343 bytes.extend_from_slice(&self.beta_g2.to_bytes()?);
344 bytes.extend_from_slice(&self.gamma_g2.to_bytes()?);
345 bytes.extend_from_slice(&self.delta_g2.to_bytes()?);
346 for g in &self.gamma_abc_g1 {
347 bytes.extend_from_slice(&g.to_bytes()?);
348 }
349 Ok(bytes)
350 }
351}
352
353#[cfg(test)]
354mod test {
355 use groth16::*;
356 use r1cs_core::{
357 lc, ConstraintSynthesizer, ConstraintSystem, ConstraintSystemRef, SynthesisError,
358 };
359
360 use super::*;
361 use algebra::{
362 bls12_377::{Bls12_377, Fq, Fr},
363 test_rng, BitIteratorLE, Field, PrimeField,
364 };
365 use r1cs_std::{bls12_377::PairingVar as Bls12_377PairingVar, boolean::Boolean, Assignment};
366 use rand::Rng;
367
368 type TestProofSystem = Groth16<Bls12_377, Bench<Fr>, Fr>;
369 type TestVerifierGadget = Groth16VerifierGadget<Bls12_377, Bls12_377PairingVar>;
370 type TestProofVar = ProofVar<Bls12_377, Bls12_377PairingVar>;
371 type TestVkVar = VerifyingKeyVar<Bls12_377, Bls12_377PairingVar>;
372
373 struct Bench<F: Field> {
374 inputs: Vec<Option<F>>,
375 num_constraints: usize,
376 }
377
378 impl<F: Field> ConstraintSynthesizer<F> for Bench<F> {
379 fn generate_constraints(self, cs: ConstraintSystemRef<F>) -> Result<(), SynthesisError> {
380 assert!(self.inputs.len() >= 2);
381 assert!(self.num_constraints >= self.inputs.len());
382
383 let mut variables: Vec<_> = Vec::with_capacity(self.inputs.len());
384 for input in self.inputs {
385 let input_var = cs.new_input_variable(|| input.get())?;
386 variables.push((input, input_var));
387 }
388
389 for i in 0..self.num_constraints {
390 let new_entry = {
391 let (input_1_val, input_1_var) = variables[i];
392 let (input_2_val, input_2_var) = variables[i + 1];
393 let result_val = input_1_val
394 .and_then(|input_1| input_2_val.map(|input_2| input_1 * &input_2));
395 let result_var = cs.new_witness_variable(|| {
396 result_val.ok_or(SynthesisError::AssignmentMissing)
397 })?;
398 cs.enforce_named_constraint(
399 format!("Enforce constraint {}", i),
400 lc!() + input_1_var,
401 lc!() + input_2_var,
402 lc!() + result_var,
403 )
404 .unwrap();
405 (result_val, result_var)
406 };
407 variables.push(new_entry);
408 }
409 Ok(())
410 }
411 }
412
413 #[test]
414 fn groth16_verifier_test() {
415 let num_inputs = 100;
416 let num_constraints = num_inputs;
417 let rng = &mut test_rng();
418 let mut inputs: Vec<Option<Fr>> = Vec::with_capacity(num_inputs);
419 for _ in 0..num_inputs {
420 inputs.push(Some(rng.gen()));
421 }
422 let params = {
423 let c = Bench::<Fr> {
424 inputs: vec![None; num_inputs],
425 num_constraints,
426 };
427
428 generate_random_parameters(c, rng).unwrap()
429 };
430
431 {
432 let proof = {
433 // Create an instance of our circuit (with the
434 // witness)
435 let c = Bench {
436 inputs: inputs.clone(),
437 num_constraints,
438 };
439 // Create a groth16 proof with our parameters.
440 create_random_proof(c, ¶ms, rng).unwrap()
441 };
442
443 // assert!(!verify_proof(&pvk, &proof, &[a]).unwrap());
444 let cs = ConstraintSystem::<Fq>::new_ref();
445
446 let inputs: Vec<_> = inputs.into_iter().map(|input| input.unwrap()).collect();
447 let mut input_gadgets = Vec::new();
448
449 {
450 for (i, input) in inputs.into_iter().enumerate() {
451 let input_bits = BitIteratorLE::new(input.into_repr()).collect::<Vec<_>>();
452
453 let input_bits =
454 Vec::<Boolean<Fq>>::new_input(cs.ns(format!("Input {}", i)), || {
455 Ok(input_bits)
456 })
457 .unwrap();
458 input_gadgets.push(input_bits);
459 }
460 }
461
462 let vk_gadget = TestVkVar::new_input(cs.ns("Vk"), || Ok(¶ms.vk)).unwrap();
463 let proof_gadget =
464 TestProofVar::new_witness(cs.ns("Proof"), || Ok(proof.clone())).unwrap();
465 println!("Time to verify!\n\n\n\n");
466 <TestVerifierGadget as NIZKVerifierGadget<TestProofSystem, Fq>>::verify(
467 &vk_gadget,
468 &input_gadgets,
469 &proof_gadget,
470 )
471 .unwrap();
472 if !cs.is_satisfied().unwrap() {
473 println!("=========================================================");
474 println!("Unsatisfied constraints:");
475 println!("{:?}", cs.which_is_unsatisfied().unwrap());
476 println!("=========================================================");
477 }
478
479 // cs.print_named_objects();
480 assert!(cs.is_satisfied().unwrap());
481 }
482 }
483}
484
485#[cfg(test)]
486mod test_recursive {
487 use groth16::*;
488 use r1cs_core::{
489 lc, ConstraintSynthesizer, ConstraintSystem, ConstraintSystemRef, SynthesisError,
490 };
491
492 use super::*;
493 use algebra::{
494 fields::{FftParameters, FpParameters},
495 mnt4_298::{Fq as MNT4Fq, FqParameters as MNT4FqParameters, Fr as MNT4Fr, MNT4_298},
496 mnt6_298::{Fq as MNT6Fq, FqParameters as MNT6FqParameters, Fr as MNT6Fr, MNT6_298},
497 test_rng, BigInteger, Field, PrimeField,
498 };
499 use r1cs_std::{
500 fields::fp::FpVar, mnt4_298::PairingVar as MNT4_298PairingVar,
501 mnt6_298::PairingVar as MNT6_298PairingVar, uint8::UInt8, Assignment,
502 };
503 use rand::Rng;
504
505 type TestProofSystem1 = Groth16<MNT6_298, Bench<MNT4Fq>, MNT6Fr>;
506 type TestVerifierGadget1 = Groth16VerifierGadget<MNT6_298, MNT6_298PairingVar>;
507 type TestProofVar1 = ProofVar<MNT6_298, MNT6_298PairingVar>;
508 type TestVkVar1 = VerifyingKeyVar<MNT6_298, MNT6_298PairingVar>;
509
510 type TestProofSystem2 = Groth16<MNT4_298, Wrapper, MNT4Fr>;
511 type TestVerifierGadget2 = Groth16VerifierGadget<MNT4_298, MNT4_298PairingVar>;
512 type TestProofVar2 = ProofVar<MNT4_298, MNT4_298PairingVar>;
513 type TestVkVar2 = VerifyingKeyVar<MNT4_298, MNT4_298PairingVar>;
514
515 #[derive(Clone)]
516 struct Bench<F: Field> {
517 inputs: Vec<Option<F>>,
518 num_constraints: usize,
519 }
520
521 impl<F: Field> ConstraintSynthesizer<F> for Bench<F> {
522 fn generate_constraints(self, cs: ConstraintSystemRef<F>) -> Result<(), SynthesisError> {
523 assert!(self.inputs.len() >= 2);
524 assert!(self.num_constraints >= self.inputs.len());
525
526 let mut variables: Vec<_> = Vec::with_capacity(self.inputs.len());
527 for input in self.inputs {
528 let input_var = cs.new_input_variable(|| input.get())?;
529 variables.push((input, input_var));
530 }
531
532 for i in 0..self.num_constraints {
533 let new_entry = {
534 let (input_1_val, input_1_var) = variables[i];
535 let (input_2_val, input_2_var) = variables[i + 1];
536 let result_val = input_1_val
537 .and_then(|input_1| input_2_val.map(|input_2| input_1 * &input_2));
538 let result_var = cs.new_witness_variable(|| {
539 result_val.ok_or(SynthesisError::AssignmentMissing)
540 })?;
541 cs.enforce_named_constraint(
542 format!("Enforce constraint {}", i),
543 lc!() + input_1_var,
544 lc!() + input_2_var,
545 lc!() + result_var,
546 )
547 .unwrap();
548 (result_val, result_var)
549 };
550 variables.push(new_entry);
551 }
552 Ok(())
553 }
554 }
555
556 struct Wrapper {
557 inputs: Vec<Option<MNT4Fq>>,
558 params: Parameters<MNT6_298>,
559 proof: Proof<MNT6_298>,
560 }
561
562 impl ConstraintSynthesizer<MNT6Fq> for Wrapper {
563 fn generate_constraints(
564 self,
565 cs: ConstraintSystemRef<MNT6Fq>,
566 ) -> Result<(), SynthesisError> {
567 let params = self.params;
568 let proof = self.proof;
569 let inputs: Vec<_> = self
570 .inputs
571 .into_iter()
572 .map(|input| input.unwrap())
573 .collect();
574 let input_gadgets;
575
576 {
577 // Chain all input values in one large byte array.
578 let input_bytes = inputs
579 .clone()
580 .into_iter()
581 .flat_map(|input| {
582 input
583 .into_repr()
584 .as_ref()
585 .iter()
586 .flat_map(|l| l.to_le_bytes().to_vec())
587 .collect::<Vec<_>>()
588 })
589 .collect::<Vec<_>>();
590
591 // Allocate this byte array as input packed into field elements.
592 let input_bytes = UInt8::new_input_vec(cs.ns("Input"), &input_bytes[..])?;
593 // 40 byte
594 let element_size = <MNT4FqParameters as FftParameters>::BigInt::NUM_LIMBS * 8;
595 input_gadgets = input_bytes
596 .chunks(element_size)
597 .map(|chunk| {
598 chunk
599 .iter()
600 .flat_map(|byte| byte.to_bits_le().unwrap())
601 .collect::<Vec<_>>()
602 })
603 .collect::<Vec<_>>();
604 }
605
606 let vk_gadget = TestVkVar1::new_witness(cs.ns("Vk"), || Ok(¶ms.vk))?;
607 let proof_gadget =
608 TestProofVar1::new_witness(cs.ns("Proof"), || Ok(proof.clone())).unwrap();
609 <TestVerifierGadget1 as NIZKVerifierGadget<TestProofSystem1, MNT6Fq>>::verify(
610 &vk_gadget,
611 &input_gadgets,
612 &proof_gadget,
613 )?;
614 Ok(())
615 }
616 }
617
618 #[test]
619 fn groth16_recursive_verifier_test() {
620 let num_inputs = 5;
621 let num_constraints = num_inputs;
622 let rng = &mut test_rng();
623 let mut inputs: Vec<Option<MNT4Fq>> = Vec::with_capacity(num_inputs);
624 for _ in 0..num_inputs {
625 inputs.push(Some(rng.gen()));
626 }
627
628 // Generate inner params and proof.
629 let inner_params = {
630 let c = Bench::<MNT4Fq> {
631 inputs: vec![None; num_inputs],
632 num_constraints,
633 };
634
635 generate_random_parameters(c, rng).unwrap()
636 };
637
638 let inner_proof = {
639 // Create an instance of our circuit (with the
640 // witness)
641 let c = Bench {
642 inputs: inputs.clone(),
643 num_constraints,
644 };
645 // Create a groth16 proof with our parameters.
646 create_random_proof(c, &inner_params, rng).unwrap()
647 };
648
649 // Generate outer params and proof.
650 let params = {
651 let c = Wrapper {
652 inputs: inputs.clone(),
653 params: inner_params.clone(),
654 proof: inner_proof.clone(),
655 };
656
657 generate_random_parameters(c, rng).unwrap()
658 };
659
660 {
661 let proof = {
662 // Create an instance of our circuit (with the
663 // witness)
664 let c = Wrapper {
665 inputs: inputs.clone(),
666 params: inner_params.clone(),
667 proof: inner_proof.clone(),
668 };
669 // Create a groth16 proof with our parameters.
670 create_random_proof(c, ¶ms, rng).unwrap()
671 };
672
673 let cs = ConstraintSystem::<MNT4Fq>::new_ref();
674
675 let inputs: Vec<_> = inputs.into_iter().map(|input| input.unwrap()).collect();
676 let mut input_gadgets = Vec::new();
677
678 {
679 let bigint_size = <MNT4FqParameters as FftParameters>::BigInt::NUM_LIMBS * 64;
680 let mut input_bits = Vec::new();
681 for (i, input) in inputs.into_iter().enumerate() {
682 let input_gadget =
683 FpVar::new_input(cs.ns(format!("Input {}", i)), || Ok(input)).unwrap();
684 let mut fp_bits = input_gadget.to_bits_le().unwrap();
685
686 // Use 320 bits per element.
687 for _ in fp_bits.len()..bigint_size {
688 fp_bits.push(Boolean::constant(false));
689 }
690 input_bits.extend_from_slice(&fp_bits);
691 }
692
693 // Pack input bits into field elements of the underlying circuit.
694 let max_size = 8 * (<MNT6FqParameters as FpParameters>::CAPACITY / 8) as usize;
695 let max_size = max_size as usize;
696 let bigint_size = <MNT6FqParameters as FftParameters>::BigInt::NUM_LIMBS * 64;
697 for chunk in input_bits.chunks(max_size) {
698 let mut chunk = chunk.to_vec();
699 let len = chunk.len();
700 for _ in len..bigint_size {
701 chunk.push(Boolean::constant(false));
702 }
703 input_gadgets.push(chunk);
704 }
705 // assert!(!verify_proof(&pvk, &proof, &[a]).unwrap());
706 }
707
708 let vk_gadget = TestVkVar2::new_input(cs.ns("Vk"), || Ok(¶ms.vk)).unwrap();
709 let proof_gadget =
710 TestProofVar2::new_witness(cs.ns("Proof"), || Ok(proof.clone())).unwrap();
711 println!("Time to verify!\n\n\n\n");
712 <TestVerifierGadget2 as NIZKVerifierGadget<TestProofSystem2, MNT4Fq>>::verify(
713 &vk_gadget,
714 &input_gadgets,
715 &proof_gadget,
716 )
717 .unwrap();
718 if !cs.is_satisfied().unwrap() {
719 println!("=========================================================");
720 println!("Unsatisfied constraints:");
721 println!("{:?}", cs.which_is_unsatisfied().unwrap());
722 println!("=========================================================");
723 }
724
725 assert!(cs.is_satisfied().unwrap());
726 }
727 }
728}