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 #[tracing::instrument(target = "r1cs", skip(cs, f))]
87 fn new_proof_unchecked<T: Borrow<Proof<E>>>(
88 cs: impl Into<Namespace<E::Fq>>,
89 f: impl FnOnce() -> Result<T, SynthesisError>,
90 mode: AllocationMode,
91 ) -> Result<Self::ProofVar, SynthesisError> {
92 let ns = cs.into();
93 let cs = ns.cs();
94 f().and_then(|proof| {
95 let proof = proof.borrow();
96 let a = CurveVar::new_variable_omit_prime_order_check(
97 r1cs_core::ns!(cs, "Proof.a"),
98 || Ok(proof.a.into_projective()),
99 mode,
100 )?;
101 let b = CurveVar::new_variable_omit_prime_order_check(
102 r1cs_core::ns!(cs, "Proof.b"),
103 || Ok(proof.b.into_projective()),
104 mode,
105 )?;
106 let c = CurveVar::new_variable_omit_prime_order_check(
107 r1cs_core::ns!(cs, "Proof.c"),
108 || Ok(proof.c.into_projective()),
109 mode,
110 )?;
111 Ok(ProofVar { a, b, c })
112 })
113 }
114
115 /// Allocates `N::Proof` in `cs` without performing
116 /// subgroup checks.
117 #[tracing::instrument(target = "r1cs", skip(cs, f))]
118 fn new_verification_key_unchecked<T: Borrow<VerifyingKey<E>>>(
119 cs: impl Into<Namespace<E::Fq>>,
120 f: impl FnOnce() -> Result<T, SynthesisError>,
121 mode: AllocationMode,
122 ) -> Result<Self::VerificationKeyVar, SynthesisError> {
123 let ns = cs.into();
124 let cs = ns.cs();
125 f().and_then(|vk| {
126 let vk = vk.borrow();
127 let alpha_g1 = P::G1Var::new_variable_omit_prime_order_check(
128 r1cs_core::ns!(cs, "alpha_g1"),
129 || Ok(vk.alpha_g1.into_projective()),
130 mode,
131 )?;
132 let beta_g2 = P::G2Var::new_variable_omit_prime_order_check(
133 r1cs_core::ns!(cs, "beta_g2"),
134 || Ok(vk.beta_g2.into_projective()),
135 mode,
136 )?;
137 let gamma_g2 = P::G2Var::new_variable_omit_prime_order_check(
138 r1cs_core::ns!(cs, "gamma_g2"),
139 || Ok(vk.gamma_g2.into_projective()),
140 mode,
141 )?;
142 let delta_g2 = P::G2Var::new_variable_omit_prime_order_check(
143 r1cs_core::ns!(cs, "delta_g2"),
144 || Ok(vk.delta_g2.into_projective()),
145 mode,
146 )?;
147
148 let gamma_abc_g1 = vk
149 .gamma_abc_g1
150 .iter()
151 .map(|g| {
152 P::G1Var::new_variable_omit_prime_order_check(
153 r1cs_core::ns!(cs, "g"),
154 || Ok(g.into_projective()),
155 mode,
156 )
157 })
158 .collect::<Result<Vec<_>, _>>()?;
159 Ok(VerifyingKeyVar {
160 alpha_g1,
161 beta_g2,
162 gamma_g2,
163 delta_g2,
164 gamma_abc_g1,
165 })
166 })
167 }
168
169 #[tracing::instrument(target = "r1cs", skip(vk, input, proof))]
170 fn verify<'a, T: 'a + ToBitsGadget<E::Fq> + ?Sized>(
171 vk: &Self::VerificationKeyVar,
172 input: impl IntoIterator<Item = &'a T>,
173 proof: &Self::ProofVar,
174 ) -> Result<Boolean<E::Fq>, SynthesisError> {
175 let pvk = vk.prepare()?;
176 <Self as NIZKVerifierGadget<Groth16<E, C, V>, E::Fq>>::verify_prepared(&pvk, input, proof)
177 }
178
179 #[tracing::instrument(target = "r1cs", skip(pvk, public_inputs, proof))]
180 fn verify_prepared<'a, T: 'a + ToBitsGadget<E::Fq> + ?Sized>(
181 pvk: &Self::PreparedVerificationKeyVar,
182 public_inputs: impl IntoIterator<Item = &'a T>,
183 proof: &Self::ProofVar,
184 ) -> Result<Boolean<E::Fq>, 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)?;
220 test.is_eq(&pvk.alpha_g1_beta_g2)
221 }
222}
223
224impl<E, P> AllocVar<PreparedVerifyingKey<E>, E::Fq> for PreparedVerifyingKeyVar<E, P>
225where
226 E: PairingEngine,
227 P: PairingVar<E>,
228{
229 #[tracing::instrument(target = "r1cs", skip(cs, f))]
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 r1cs_core::ns!(cs, "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 r1cs_core::ns!(cs, "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 r1cs_core::ns!(cs, "delta_g2_neg_pc"),
254 || Ok(pvk.delta_g2_neg_pc.clone()),
255 mode,
256 )?;
257
258 let gamma_abc_g1 = Vec::new_variable(
259 r1cs_core::ns!(cs, "gamma_abc_g1"),
260 || Ok(pvk.gamma_abc_g1.clone()),
261 mode,
262 )?;
263
264 Ok(Self {
265 alpha_g1_beta_g2,
266 gamma_g2_neg_pc,
267 delta_g2_neg_pc,
268 gamma_abc_g1,
269 })
270 })
271 }
272}
273
274impl<E, P> AllocVar<VerifyingKey<E>, E::Fq> for VerifyingKeyVar<E, P>
275where
276 E: PairingEngine,
277
278 P: PairingVar<E>,
279{
280 #[tracing::instrument(target = "r1cs", skip(cs, f))]
281 fn new_variable<T: Borrow<VerifyingKey<E>>>(
282 cs: impl Into<Namespace<E::Fq>>,
283 f: impl FnOnce() -> Result<T, SynthesisError>,
284 mode: AllocationMode,
285 ) -> Result<Self, SynthesisError> {
286 let ns = cs.into();
287 let cs = ns.cs();
288
289 f().and_then(|vk| {
290 let VerifyingKey {
291 alpha_g1,
292 beta_g2,
293 gamma_g2,
294 delta_g2,
295 gamma_abc_g1,
296 } = vk.borrow().clone();
297 let alpha_g1 =
298 P::G1Var::new_variable(r1cs_core::ns!(cs, "alpha_g1"), || Ok(alpha_g1), mode)?;
299 let beta_g2 =
300 P::G2Var::new_variable(r1cs_core::ns!(cs, "beta_g2"), || Ok(beta_g2), mode)?;
301 let gamma_g2 =
302 P::G2Var::new_variable(r1cs_core::ns!(cs, "gamma_g2"), || Ok(gamma_g2), mode)?;
303 let delta_g2 =
304 P::G2Var::new_variable(r1cs_core::ns!(cs, "delta_g2"), || Ok(delta_g2), mode)?;
305
306 let gamma_abc_g1 = Vec::new_variable(cs.clone(), || Ok(gamma_abc_g1), mode)?;
307 Ok(Self {
308 alpha_g1,
309 beta_g2,
310 gamma_g2,
311 delta_g2,
312 gamma_abc_g1,
313 })
314 })
315 }
316}
317
318impl<E, P> AllocVar<Proof<E>, E::Fq> for ProofVar<E, P>
319where
320 E: PairingEngine,
321 P: PairingVar<E>,
322{
323 #[tracing::instrument(target = "r1cs", skip(cs, f))]
324 fn new_variable<T: Borrow<Proof<E>>>(
325 cs: impl Into<Namespace<E::Fq>>,
326 f: impl FnOnce() -> Result<T, SynthesisError>,
327 mode: AllocationMode,
328 ) -> Result<Self, SynthesisError> {
329 let ns = cs.into();
330 let cs = ns.cs();
331
332 f().and_then(|proof| {
333 let Proof { a, b, c } = proof.borrow().clone();
334 let a = P::G1Var::new_variable(r1cs_core::ns!(cs, "a"), || Ok(a), mode)?;
335 let b = P::G2Var::new_variable(r1cs_core::ns!(cs, "b"), || Ok(b), mode)?;
336 let c = P::G1Var::new_variable(r1cs_core::ns!(cs, "c"), || Ok(c), mode)?;
337 Ok(Self { a, b, c })
338 })
339 }
340}
341
342impl<E, P> ToBytesGadget<E::Fq> for VerifyingKeyVar<E, P>
343where
344 E: PairingEngine,
345 P: PairingVar<E>,
346{
347 #[inline]
348 #[tracing::instrument(target = "r1cs", skip(self))]
349 fn to_bytes(&self) -> Result<Vec<UInt8<E::Fq>>, SynthesisError> {
350 let mut bytes = Vec::new();
351 bytes.extend_from_slice(&self.alpha_g1.to_bytes()?);
352 bytes.extend_from_slice(&self.beta_g2.to_bytes()?);
353 bytes.extend_from_slice(&self.gamma_g2.to_bytes()?);
354 bytes.extend_from_slice(&self.delta_g2.to_bytes()?);
355 for g in &self.gamma_abc_g1 {
356 bytes.extend_from_slice(&g.to_bytes()?);
357 }
358 Ok(bytes)
359 }
360}
361
362#[cfg(test)]
363mod test {
364 use groth16::*;
365 use r1cs_core::{
366 lc, ConstraintSynthesizer, ConstraintSystem, ConstraintSystemRef, SynthesisError,
367 };
368
369 use super::*;
370 use algebra::{
371 bls12_377::{Bls12_377, Fq, Fr},
372 test_rng, BitIteratorLE, Field, PrimeField,
373 };
374 use r1cs_std::{bls12_377::PairingVar as Bls12_377PairingVar, boolean::Boolean, Assignment};
375 use rand::Rng;
376
377 type TestProofSystem = Groth16<Bls12_377, Bench<Fr>, Fr>;
378 type TestVerifierGadget = Groth16VerifierGadget<Bls12_377, Bls12_377PairingVar>;
379 type TestProofVar = ProofVar<Bls12_377, Bls12_377PairingVar>;
380 type TestVkVar = VerifyingKeyVar<Bls12_377, Bls12_377PairingVar>;
381
382 struct Bench<F: Field> {
383 inputs: Vec<Option<F>>,
384 num_constraints: usize,
385 }
386
387 impl<F: Field> ConstraintSynthesizer<F> for Bench<F> {
388 fn generate_constraints(self, cs: ConstraintSystemRef<F>) -> Result<(), SynthesisError> {
389 assert!(self.inputs.len() >= 2);
390 assert!(self.num_constraints >= self.inputs.len());
391
392 let mut variables: Vec<_> = Vec::with_capacity(self.inputs.len());
393 for input in self.inputs {
394 let input_var = cs.new_input_variable(|| input.get())?;
395 variables.push((input, input_var));
396 }
397
398 for i in 0..self.num_constraints {
399 let new_entry = {
400 let (input_1_val, input_1_var) = variables[i];
401 let (input_2_val, input_2_var) = variables[i + 1];
402 let result_val = input_1_val
403 .and_then(|input_1| input_2_val.map(|input_2| input_1 * &input_2));
404 let result_var = cs.new_witness_variable(|| {
405 result_val.ok_or(SynthesisError::AssignmentMissing)
406 })?;
407 cs.enforce_constraint(
408 lc!() + input_1_var,
409 lc!() + input_2_var,
410 lc!() + result_var,
411 )
412 .unwrap();
413 (result_val, result_var)
414 };
415 variables.push(new_entry);
416 }
417 Ok(())
418 }
419 }
420
421 #[test]
422 fn groth16_verifier_test() {
423 let num_inputs = 100;
424 let num_constraints = num_inputs;
425 let rng = &mut test_rng();
426 let mut inputs: Vec<Option<Fr>> = Vec::with_capacity(num_inputs);
427 for _ in 0..num_inputs {
428 inputs.push(Some(rng.gen()));
429 }
430 let params = {
431 let c = Bench::<Fr> {
432 inputs: vec![None; num_inputs],
433 num_constraints,
434 };
435
436 generate_random_parameters(c, rng).unwrap()
437 };
438
439 {
440 let proof = {
441 // Create an instance of our circuit (with the
442 // witness)
443 let c = Bench {
444 inputs: inputs.clone(),
445 num_constraints,
446 };
447 // Create a groth16 proof with our parameters.
448 create_random_proof(c, ¶ms, rng).unwrap()
449 };
450
451 // assert!(!verify_proof(&pvk, &proof, &[a]).unwrap());
452 let cs = ConstraintSystem::<Fq>::new_ref();
453
454 let inputs: Vec<_> = inputs.into_iter().map(|input| input.unwrap()).collect();
455 let mut input_gadgets = Vec::new();
456
457 {
458 for input in inputs.into_iter() {
459 let input_bits = BitIteratorLE::new(input.into_repr()).collect::<Vec<_>>();
460
461 let input_bits =
462 Vec::<Boolean<Fq>>::new_input(r1cs_core::ns!(cs, "Input"), || {
463 Ok(input_bits)
464 })
465 .unwrap();
466 input_gadgets.push(input_bits);
467 }
468 }
469
470 let vk_gadget =
471 TestVkVar::new_input(r1cs_core::ns!(cs, "Vk"), || Ok(¶ms.vk)).unwrap();
472 let proof_gadget =
473 TestProofVar::new_witness(r1cs_core::ns!(cs, "Proof"), || Ok(proof.clone()))
474 .unwrap();
475 println!("Time to verify!\n\n\n\n");
476 <TestVerifierGadget as NIZKVerifierGadget<TestProofSystem, Fq>>::verify(
477 &vk_gadget,
478 &input_gadgets,
479 &proof_gadget,
480 )
481 .unwrap()
482 .enforce_equal(&Boolean::TRUE)
483 .unwrap();
484 if !cs.is_satisfied().unwrap() {
485 println!("=========================================================");
486 println!("Unsatisfied constraints:");
487 println!("{:?}", cs.which_is_unsatisfied().unwrap());
488 println!("=========================================================");
489 }
490
491 // cs.print_named_objects();
492 assert!(cs.is_satisfied().unwrap());
493 }
494 }
495}
496
497#[cfg(test)]
498mod test_recursive {
499 use groth16::*;
500 use r1cs_core::{
501 lc, ConstraintSynthesizer, ConstraintSystem, ConstraintSystemRef, SynthesisError,
502 };
503
504 use super::*;
505 use algebra::{
506 fields::{FftParameters, FpParameters},
507 mnt4_298::{Fq as MNT4Fq, FqParameters as MNT4FqParameters, Fr as MNT4Fr, MNT4_298},
508 mnt6_298::{Fq as MNT6Fq, FqParameters as MNT6FqParameters, Fr as MNT6Fr, MNT6_298},
509 test_rng, BigInteger, Field, PrimeField,
510 };
511 use r1cs_std::{
512 fields::fp::FpVar, mnt4_298::PairingVar as MNT4_298PairingVar,
513 mnt6_298::PairingVar as MNT6_298PairingVar, uint8::UInt8, Assignment,
514 };
515 use rand::Rng;
516
517 type TestProofSystem1 = Groth16<MNT6_298, Bench<MNT4Fq>, MNT6Fr>;
518 type TestVerifierGadget1 = Groth16VerifierGadget<MNT6_298, MNT6_298PairingVar>;
519 type TestProofVar1 = ProofVar<MNT6_298, MNT6_298PairingVar>;
520 type TestVkVar1 = VerifyingKeyVar<MNT6_298, MNT6_298PairingVar>;
521
522 type TestProofSystem2 = Groth16<MNT4_298, Wrapper, MNT4Fr>;
523 type TestVerifierGadget2 = Groth16VerifierGadget<MNT4_298, MNT4_298PairingVar>;
524 type TestProofVar2 = ProofVar<MNT4_298, MNT4_298PairingVar>;
525 type TestVkVar2 = VerifyingKeyVar<MNT4_298, MNT4_298PairingVar>;
526
527 #[derive(Clone)]
528 struct Bench<F: Field> {
529 inputs: Vec<Option<F>>,
530 num_constraints: usize,
531 }
532
533 impl<F: Field> ConstraintSynthesizer<F> for Bench<F> {
534 fn generate_constraints(self, cs: ConstraintSystemRef<F>) -> Result<(), SynthesisError> {
535 assert!(self.inputs.len() >= 2);
536 assert!(self.num_constraints >= self.inputs.len());
537
538 let mut variables: Vec<_> = Vec::with_capacity(self.inputs.len());
539 for input in self.inputs {
540 let input_var = cs.new_input_variable(|| input.get())?;
541 variables.push((input, input_var));
542 }
543
544 for i in 0..self.num_constraints {
545 let new_entry = {
546 let (input_1_val, input_1_var) = variables[i];
547 let (input_2_val, input_2_var) = variables[i + 1];
548 let result_val = input_1_val
549 .and_then(|input_1| input_2_val.map(|input_2| input_1 * &input_2));
550 let result_var = cs.new_witness_variable(|| {
551 result_val.ok_or(SynthesisError::AssignmentMissing)
552 })?;
553 cs.enforce_constraint(
554 lc!() + input_1_var,
555 lc!() + input_2_var,
556 lc!() + result_var,
557 )
558 .unwrap();
559 (result_val, result_var)
560 };
561 variables.push(new_entry);
562 }
563 Ok(())
564 }
565 }
566
567 struct Wrapper {
568 inputs: Vec<Option<MNT4Fq>>,
569 params: Parameters<MNT6_298>,
570 proof: Proof<MNT6_298>,
571 }
572
573 impl ConstraintSynthesizer<MNT6Fq> for Wrapper {
574 fn generate_constraints(
575 self,
576 cs: ConstraintSystemRef<MNT6Fq>,
577 ) -> Result<(), SynthesisError> {
578 let params = self.params;
579 let proof = self.proof;
580 let inputs: Vec<_> = self
581 .inputs
582 .into_iter()
583 .map(|input| input.unwrap())
584 .collect();
585 let input_gadgets;
586
587 {
588 // Chain all input values in one large byte array.
589 let input_bytes = inputs
590 .clone()
591 .into_iter()
592 .flat_map(|input| {
593 input
594 .into_repr()
595 .as_ref()
596 .iter()
597 .flat_map(|l| l.to_le_bytes().to_vec())
598 .collect::<Vec<_>>()
599 })
600 .collect::<Vec<_>>();
601
602 // Allocate this byte array as input packed into field elements.
603 let input_bytes =
604 UInt8::new_input_vec(r1cs_core::ns!(cs, "Input"), &input_bytes[..])?;
605 // 40 byte
606 let element_size = <MNT4FqParameters as FftParameters>::BigInt::NUM_LIMBS * 8;
607 input_gadgets = input_bytes
608 .chunks(element_size)
609 .map(|chunk| {
610 chunk
611 .iter()
612 .flat_map(|byte| byte.to_bits_le().unwrap())
613 .collect::<Vec<_>>()
614 })
615 .collect::<Vec<_>>();
616 }
617
618 let vk_gadget = TestVkVar1::new_witness(r1cs_core::ns!(cs, "Vk"), || Ok(¶ms.vk))?;
619 let proof_gadget =
620 TestProofVar1::new_witness(r1cs_core::ns!(cs, "Proof"), || Ok(proof.clone()))
621 .unwrap();
622 <TestVerifierGadget1 as NIZKVerifierGadget<TestProofSystem1, MNT6Fq>>::verify(
623 &vk_gadget,
624 &input_gadgets,
625 &proof_gadget,
626 )?
627 .enforce_equal(&Boolean::TRUE)?;
628 Ok(())
629 }
630 }
631
632 #[test]
633 fn groth16_recursive_verifier_test() {
634 let num_inputs = 5;
635 let num_constraints = num_inputs;
636 let rng = &mut test_rng();
637 let mut inputs: Vec<Option<MNT4Fq>> = Vec::with_capacity(num_inputs);
638 for _ in 0..num_inputs {
639 inputs.push(Some(rng.gen()));
640 }
641
642 // Generate inner params and proof.
643 let inner_params = {
644 let c = Bench::<MNT4Fq> {
645 inputs: vec![None; num_inputs],
646 num_constraints,
647 };
648
649 generate_random_parameters(c, rng).unwrap()
650 };
651
652 let inner_proof = {
653 // Create an instance of our circuit (with the
654 // witness)
655 let c = Bench {
656 inputs: inputs.clone(),
657 num_constraints,
658 };
659 // Create a groth16 proof with our parameters.
660 create_random_proof(c, &inner_params, rng).unwrap()
661 };
662
663 // Generate outer params and proof.
664 let params = {
665 let c = Wrapper {
666 inputs: inputs.clone(),
667 params: inner_params.clone(),
668 proof: inner_proof.clone(),
669 };
670
671 generate_random_parameters(c, rng).unwrap()
672 };
673
674 {
675 let proof = {
676 // Create an instance of our circuit (with the
677 // witness)
678 let c = Wrapper {
679 inputs: inputs.clone(),
680 params: inner_params.clone(),
681 proof: inner_proof.clone(),
682 };
683 // Create a groth16 proof with our parameters.
684 create_random_proof(c, ¶ms, rng).unwrap()
685 };
686
687 let cs = ConstraintSystem::<MNT4Fq>::new_ref();
688
689 let inputs: Vec<_> = inputs.into_iter().map(|input| input.unwrap()).collect();
690 let mut input_gadgets = Vec::new();
691
692 {
693 let bigint_size = <MNT4FqParameters as FftParameters>::BigInt::NUM_LIMBS * 64;
694 let mut input_bits = Vec::new();
695 for input in inputs.into_iter() {
696 let input_gadget =
697 FpVar::new_input(r1cs_core::ns!(cs, "Input"), || Ok(input)).unwrap();
698 let mut fp_bits = input_gadget.to_bits_le().unwrap();
699
700 // Use 320 bits per element.
701 for _ in fp_bits.len()..bigint_size {
702 fp_bits.push(Boolean::constant(false));
703 }
704 input_bits.extend_from_slice(&fp_bits);
705 }
706
707 // Pack input bits into field elements of the underlying circuit.
708 let max_size = 8 * (<MNT6FqParameters as FpParameters>::CAPACITY / 8) as usize;
709 let max_size = max_size as usize;
710 let bigint_size = <MNT6FqParameters as FftParameters>::BigInt::NUM_LIMBS * 64;
711 for chunk in input_bits.chunks(max_size) {
712 let mut chunk = chunk.to_vec();
713 let len = chunk.len();
714 for _ in len..bigint_size {
715 chunk.push(Boolean::constant(false));
716 }
717 input_gadgets.push(chunk);
718 }
719 // assert!(!verify_proof(&pvk, &proof, &[a]).unwrap());
720 }
721
722 let vk_gadget =
723 TestVkVar2::new_input(r1cs_core::ns!(cs, "Vk"), || Ok(¶ms.vk)).unwrap();
724 let proof_gadget =
725 TestProofVar2::new_witness(r1cs_core::ns!(cs, "Proof"), || Ok(proof.clone()))
726 .unwrap();
727 println!("Time to verify!\n\n\n\n");
728 <TestVerifierGadget2 as NIZKVerifierGadget<TestProofSystem2, MNT4Fq>>::verify(
729 &vk_gadget,
730 &input_gadgets,
731 &proof_gadget,
732 )
733 .unwrap()
734 .enforce_equal(&Boolean::TRUE)
735 .unwrap();
736 if !cs.is_satisfied().unwrap() {
737 println!("=========================================================");
738 println!("Unsatisfied constraints:");
739 println!("{:?}", cs.which_is_unsatisfied().unwrap());
740 println!("=========================================================");
741 }
742
743 assert!(cs.is_satisfied().unwrap());
744 }
745 }
746}