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