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