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_constant<T, CS: ConstraintSystem<ConstraintF>>(
178 mut cs: CS,
179 val: T,
180 ) -> Result<Self, SynthesisError>
181 where
182 T: Borrow<VerifyingKey<PairingE>>,
183 {
184 let VerifyingKey {
185 alpha_g1,
186 beta_g2,
187 gamma_g2,
188 delta_g2,
189 gamma_abc_g1,
190 } = val.borrow().clone();
191 let alpha_g1 =
192 P::G1Gadget::alloc_constant(cs.ns(|| "alpha_g1"), alpha_g1.into_projective())?;
193 let beta_g2 = P::G2Gadget::alloc_constant(cs.ns(|| "beta_g2"), beta_g2.into_projective())?;
194 let gamma_g2 =
195 P::G2Gadget::alloc_constant(cs.ns(|| "gamma_g2"), gamma_g2.into_projective())?;
196 let delta_g2 =
197 P::G2Gadget::alloc_constant(cs.ns(|| "delta_g2"), delta_g2.into_projective())?;
198
199 let gamma_abc_g1 = gamma_abc_g1
200 .into_iter()
201 .enumerate()
202 .map(|(i, gamma_abc_i)| {
203 P::G1Gadget::alloc_constant(
204 cs.ns(|| format!("gamma_abc_{}", i)),
205 gamma_abc_i.into_projective(),
206 )
207 })
208 .collect::<Vec<_>>()
209 .into_iter()
210 .collect::<Result<_, _>>()?;
211 Ok(Self {
212 alpha_g1,
213 beta_g2,
214 gamma_g2,
215 delta_g2,
216 gamma_abc_g1,
217 })
218 }
219
220 #[inline]
221 fn alloc<FN, T, CS: ConstraintSystem<ConstraintF>>(
222 mut cs: CS,
223 value_gen: FN,
224 ) -> Result<Self, SynthesisError>
225 where
226 FN: FnOnce() -> Result<T, SynthesisError>,
227 T: Borrow<VerifyingKey<PairingE>>,
228 {
229 value_gen().and_then(|vk| {
230 let VerifyingKey {
231 alpha_g1,
232 beta_g2,
233 gamma_g2,
234 delta_g2,
235 gamma_abc_g1,
236 } = vk.borrow().clone();
237 let alpha_g1 =
238 P::G1Gadget::alloc(cs.ns(|| "alpha_g1"), || Ok(alpha_g1.into_projective()))?;
239 let beta_g2 =
240 P::G2Gadget::alloc(cs.ns(|| "beta_g2"), || Ok(beta_g2.into_projective()))?;
241 let gamma_g2 =
242 P::G2Gadget::alloc(cs.ns(|| "gamma_g2"), || Ok(gamma_g2.into_projective()))?;
243 let delta_g2 =
244 P::G2Gadget::alloc(cs.ns(|| "delta_g2"), || Ok(delta_g2.into_projective()))?;
245
246 let gamma_abc_g1 = gamma_abc_g1
247 .into_iter()
248 .enumerate()
249 .map(|(i, gamma_abc_i)| {
250 P::G1Gadget::alloc(cs.ns(|| format!("gamma_abc_{}", i)), || {
251 Ok(gamma_abc_i.into_projective())
252 })
253 })
254 .collect::<Vec<_>>()
255 .into_iter()
256 .collect::<Result<_, _>>()?;
257 Ok(Self {
258 alpha_g1,
259 beta_g2,
260 gamma_g2,
261 delta_g2,
262 gamma_abc_g1,
263 })
264 })
265 }
266
267 #[inline]
268 fn alloc_input<FN, T, CS: ConstraintSystem<ConstraintF>>(
269 mut cs: CS,
270 value_gen: FN,
271 ) -> Result<Self, SynthesisError>
272 where
273 FN: FnOnce() -> Result<T, SynthesisError>,
274 T: Borrow<VerifyingKey<PairingE>>,
275 {
276 value_gen().and_then(|vk| {
277 let VerifyingKey {
278 alpha_g1,
279 beta_g2,
280 gamma_g2,
281 delta_g2,
282 gamma_abc_g1,
283 } = vk.borrow().clone();
284 let alpha_g1 =
285 P::G1Gadget::alloc_input(cs.ns(|| "alpha_g1"), || Ok(alpha_g1.into_projective()))?;
286 let beta_g2 =
287 P::G2Gadget::alloc_input(cs.ns(|| "beta_g2"), || Ok(beta_g2.into_projective()))?;
288 let gamma_g2 =
289 P::G2Gadget::alloc_input(cs.ns(|| "gamma_g2"), || Ok(gamma_g2.into_projective()))?;
290 let delta_g2 =
291 P::G2Gadget::alloc_input(cs.ns(|| "delta_g2"), || Ok(delta_g2.into_projective()))?;
292
293 let gamma_abc_g1 = gamma_abc_g1
294 .into_iter()
295 .enumerate()
296 .map(|(i, gamma_abc_i)| {
297 P::G1Gadget::alloc_input(cs.ns(|| format!("gamma_abc_{}", i)), || {
298 Ok(gamma_abc_i.into_projective())
299 })
300 })
301 .collect::<Vec<_>>()
302 .into_iter()
303 .collect::<Result<_, _>>()?;
304
305 Ok(Self {
306 alpha_g1,
307 beta_g2,
308 gamma_g2,
309 delta_g2,
310 gamma_abc_g1,
311 })
312 })
313 }
314}
315
316impl<PairingE, ConstraintF, P> AllocGadget<Proof<PairingE>, ConstraintF>
317 for ProofGadget<PairingE, ConstraintF, P>
318where
319 PairingE: PairingEngine,
320 ConstraintF: Field,
321 P: PairingGadget<PairingE, ConstraintF>,
322{
323 #[inline]
324 fn alloc_constant<T, CS: ConstraintSystem<ConstraintF>>(
325 mut cs: CS,
326 val: T,
327 ) -> Result<Self, SynthesisError>
328 where
329 T: Borrow<Proof<PairingE>>,
330 {
331 let Proof { a, b, c } = val.borrow().clone();
332 let a = P::G1Gadget::alloc_constant(cs.ns(|| "a"), a.into_projective())?;
333 let b = P::G2Gadget::alloc_constant(cs.ns(|| "b"), b.into_projective())?;
334 let c = P::G1Gadget::alloc_constant(cs.ns(|| "c"), c.into_projective())?;
335 Ok(Self { a, b, c })
336 }
337
338 #[inline]
339 fn alloc<FN, T, CS: ConstraintSystem<ConstraintF>>(
340 mut cs: CS,
341 value_gen: FN,
342 ) -> Result<Self, SynthesisError>
343 where
344 FN: FnOnce() -> Result<T, SynthesisError>,
345 T: Borrow<Proof<PairingE>>,
346 {
347 value_gen().and_then(|proof| {
348 let Proof { a, b, c } = proof.borrow().clone();
349 let a = P::G1Gadget::alloc_checked(cs.ns(|| "a"), || Ok(a.into_projective()))?;
350 let b = P::G2Gadget::alloc_checked(cs.ns(|| "b"), || Ok(b.into_projective()))?;
351 let c = P::G1Gadget::alloc_checked(cs.ns(|| "c"), || Ok(c.into_projective()))?;
352 Ok(Self { a, b, c })
353 })
354 }
355
356 #[inline]
357 fn alloc_input<FN, T, CS: ConstraintSystem<ConstraintF>>(
358 mut cs: CS,
359 value_gen: FN,
360 ) -> Result<Self, SynthesisError>
361 where
362 FN: FnOnce() -> Result<T, SynthesisError>,
363 T: Borrow<Proof<PairingE>>,
364 {
365 value_gen().and_then(|proof| {
366 let Proof { a, b, c } = proof.borrow().clone();
367 // We don't need to check here because the prime order check can be performed
368 // in plain.
369 let a = P::G1Gadget::alloc_input(cs.ns(|| "a"), || Ok(a.into_projective()))?;
370 let b = P::G2Gadget::alloc_input(cs.ns(|| "b"), || Ok(b.into_projective()))?;
371 let c = P::G1Gadget::alloc_input(cs.ns(|| "c"), || Ok(c.into_projective()))?;
372 Ok(Self { a, b, c })
373 })
374 }
375}
376
377impl<PairingE, ConstraintF, P> ToBytesGadget<ConstraintF>
378 for VerifyingKeyGadget<PairingE, ConstraintF, P>
379where
380 PairingE: PairingEngine,
381 ConstraintF: Field,
382 P: PairingGadget<PairingE, ConstraintF>,
383{
384 #[inline]
385 fn to_bytes<CS: ConstraintSystem<ConstraintF>>(
386 &self,
387 mut cs: CS,
388 ) -> Result<Vec<UInt8>, SynthesisError> {
389 let mut bytes = Vec::new();
390 bytes.extend_from_slice(&self.alpha_g1.to_bytes(&mut cs.ns(|| "alpha_g1 to bytes"))?);
391 bytes.extend_from_slice(&self.beta_g2.to_bytes(&mut cs.ns(|| "beta_g2 to bytes"))?);
392 bytes.extend_from_slice(&self.gamma_g2.to_bytes(&mut cs.ns(|| "gamma_g2 to bytes"))?);
393 bytes.extend_from_slice(&self.delta_g2.to_bytes(&mut cs.ns(|| "delta_g2 to bytes"))?);
394 for (i, g) in self.gamma_abc_g1.iter().enumerate() {
395 let mut cs = cs.ns(|| format!("Iteration {}", i));
396 bytes.extend_from_slice(&g.to_bytes(&mut cs.ns(|| "g"))?);
397 }
398 Ok(bytes)
399 }
400}
401
402#[cfg(test)]
403mod test {
404 use groth16::*;
405 use r1cs_core::{ConstraintSynthesizer, ConstraintSystem, SynthesisError};
406
407 use super::*;
408 use algebra::{
409 bls12_377::{Bls12_377, Fq, Fr},
410 test_rng, BitIterator, PrimeField,
411 };
412 use r1cs_std::{
413 bls12_377::PairingGadget as Bls12_377PairingGadget, boolean::Boolean,
414 test_constraint_system::TestConstraintSystem,
415 };
416 use rand::Rng;
417
418 type TestProofSystem = Groth16<Bls12_377, Bench<Fr>, Fr>;
419 type TestVerifierGadget = Groth16VerifierGadget<Bls12_377, Fq, Bls12_377PairingGadget>;
420 type TestProofGadget = ProofGadget<Bls12_377, Fq, Bls12_377PairingGadget>;
421 type TestVkGadget = VerifyingKeyGadget<Bls12_377, Fq, Bls12_377PairingGadget>;
422
423 struct Bench<F: Field> {
424 inputs: Vec<Option<F>>,
425 num_constraints: usize,
426 }
427
428 impl<F: Field> ConstraintSynthesizer<F> for Bench<F> {
429 fn generate_constraints<CS: ConstraintSystem<F>>(
430 self,
431 cs: &mut CS,
432 ) -> Result<(), SynthesisError> {
433 assert!(self.inputs.len() >= 2);
434 assert!(self.num_constraints >= self.inputs.len());
435
436 let mut variables: Vec<_> = Vec::with_capacity(self.inputs.len());
437 for (i, input) in self.inputs.into_iter().enumerate() {
438 let input_var = cs.alloc_input(
439 || format!("Input {}", i),
440 || input.ok_or(SynthesisError::AssignmentMissing),
441 )?;
442 variables.push((input, input_var));
443 }
444
445 for i in 0..self.num_constraints {
446 let new_entry = {
447 let (input_1_val, input_1_var) = variables[i];
448 let (input_2_val, input_2_var) = variables[i + 1];
449 let result_val = input_1_val
450 .and_then(|input_1| input_2_val.map(|input_2| input_1 * &input_2));
451 let result_var = cs.alloc(
452 || format!("Result {}", i),
453 || result_val.ok_or(SynthesisError::AssignmentMissing),
454 )?;
455 cs.enforce(
456 || format!("Enforce constraint {}", i),
457 |lc| lc + input_1_var,
458 |lc| lc + input_2_var,
459 |lc| lc + result_var,
460 );
461 (result_val, result_var)
462 };
463 variables.push(new_entry);
464 }
465 Ok(())
466 }
467 }
468
469 #[test]
470 fn groth16_verifier_test() {
471 let num_inputs = 100;
472 let num_constraints = num_inputs;
473 let rng = &mut test_rng();
474 let mut inputs: Vec<Option<Fr>> = Vec::with_capacity(num_inputs);
475 for _ in 0..num_inputs {
476 inputs.push(Some(rng.gen()));
477 }
478 let params = {
479 let c = Bench::<Fr> {
480 inputs: vec![None; num_inputs],
481 num_constraints,
482 };
483
484 generate_random_parameters(c, rng).unwrap()
485 };
486
487 {
488 let proof = {
489 // Create an instance of our circuit (with the
490 // witness)
491 let c = Bench {
492 inputs: inputs.clone(),
493 num_constraints,
494 };
495 // Create a groth16 proof with our parameters.
496 create_random_proof(c, ¶ms, rng).unwrap()
497 };
498
499 // assert!(!verify_proof(&pvk, &proof, &[a]).unwrap());
500 let mut cs = TestConstraintSystem::<Fq>::new();
501
502 let inputs: Vec<_> = inputs.into_iter().map(|input| input.unwrap()).collect();
503 let mut input_gadgets = Vec::new();
504
505 {
506 let mut cs = cs.ns(|| "Allocate Input");
507 for (i, input) in inputs.into_iter().enumerate() {
508 let mut input_bits = BitIterator::new(input.into_repr()).collect::<Vec<_>>();
509 // Input must be in little-endian, but BitIterator outputs in big-endian.
510 input_bits.reverse();
511
512 let input_bits =
513 Vec::<Boolean>::alloc_input(cs.ns(|| format!("Input {}", i)), || {
514 Ok(input_bits)
515 })
516 .unwrap();
517 input_gadgets.push(input_bits);
518 }
519 }
520
521 let vk_gadget = TestVkGadget::alloc_input(cs.ns(|| "Vk"), || Ok(¶ms.vk)).unwrap();
522 let proof_gadget =
523 TestProofGadget::alloc(cs.ns(|| "Proof"), || Ok(proof.clone())).unwrap();
524 println!("Time to verify!\n\n\n\n");
525 <TestVerifierGadget as NIZKVerifierGadget<TestProofSystem, Fq>>::check_verify(
526 cs.ns(|| "Verify"),
527 &vk_gadget,
528 input_gadgets.iter(),
529 &proof_gadget,
530 )
531 .unwrap();
532 if !cs.is_satisfied() {
533 println!("=========================================================");
534 println!("Unsatisfied constraints:");
535 println!("{:?}", cs.which_is_unsatisfied().unwrap());
536 println!("=========================================================");
537 }
538
539 // cs.print_named_objects();
540 assert!(cs.is_satisfied());
541 }
542 }
543}
544
545#[cfg(test)]
546mod test_recursive {
547 use groth16::*;
548 use r1cs_core::{ConstraintSynthesizer, ConstraintSystem, SynthesisError};
549
550 use super::*;
551 use algebra::{
552 fields::FpParameters,
553 mnt4_298::{Fq as MNT4Fq, FqParameters as MNT4FqParameters, Fr as MNT4Fr, MNT4_298},
554 mnt6_298::{Fq as MNT6Fq, FqParameters as MNT6FqParameters, Fr as MNT6Fr, MNT6_298},
555 test_rng, BigInteger, PrimeField,
556 };
557 use r1cs_std::{
558 fields::fp::FpGadget, mnt4_298::PairingGadget as MNT4_298PairingGadget,
559 mnt6_298::PairingGadget as MNT6_298PairingGadget,
560 test_constraint_system::TestConstraintSystem, uint8::UInt8,
561 };
562 use rand::Rng;
563
564 type TestProofSystem1 = Groth16<MNT6_298, Bench<MNT4Fq>, MNT6Fr>;
565 type TestVerifierGadget1 = Groth16VerifierGadget<MNT6_298, MNT6Fq, MNT6_298PairingGadget>;
566 type TestProofGadget1 = ProofGadget<MNT6_298, MNT6Fq, MNT6_298PairingGadget>;
567 type TestVkGadget1 = VerifyingKeyGadget<MNT6_298, MNT6Fq, MNT6_298PairingGadget>;
568
569 type TestProofSystem2 = Groth16<MNT4_298, Wrapper, MNT4Fr>;
570 type TestVerifierGadget2 = Groth16VerifierGadget<MNT4_298, MNT4Fq, MNT4_298PairingGadget>;
571 type TestProofGadget2 = ProofGadget<MNT4_298, MNT4Fq, MNT4_298PairingGadget>;
572 type TestVkGadget2 = VerifyingKeyGadget<MNT4_298, MNT4Fq, MNT4_298PairingGadget>;
573
574 #[derive(Clone)]
575 struct Bench<F: Field> {
576 inputs: Vec<Option<F>>,
577 num_constraints: usize,
578 }
579
580 impl<F: Field> ConstraintSynthesizer<F> for Bench<F> {
581 fn generate_constraints<CS: ConstraintSystem<F>>(
582 self,
583 cs: &mut CS,
584 ) -> Result<(), SynthesisError> {
585 assert!(self.inputs.len() >= 2);
586 assert!(self.num_constraints >= self.inputs.len());
587
588 let mut variables: Vec<_> = Vec::with_capacity(self.inputs.len());
589 for (i, input) in self.inputs.into_iter().enumerate() {
590 let input_var = cs.alloc_input(
591 || format!("Input {}", i),
592 || input.ok_or(SynthesisError::AssignmentMissing),
593 )?;
594 variables.push((input, input_var));
595 }
596
597 for i in 0..self.num_constraints {
598 let new_entry = {
599 let (input_1_val, input_1_var) = variables[i];
600 let (input_2_val, input_2_var) = variables[i + 1];
601 let result_val = input_1_val
602 .and_then(|input_1| input_2_val.map(|input_2| input_1 * &input_2));
603 let result_var = cs.alloc(
604 || format!("Result {}", i),
605 || result_val.ok_or(SynthesisError::AssignmentMissing),
606 )?;
607 cs.enforce(
608 || format!("Enforce constraint {}", i),
609 |lc| lc + input_1_var,
610 |lc| lc + input_2_var,
611 |lc| lc + result_var,
612 );
613 (result_val, result_var)
614 };
615 variables.push(new_entry);
616 }
617 Ok(())
618 }
619 }
620
621 struct Wrapper {
622 inputs: Vec<Option<MNT4Fq>>,
623 params: Parameters<MNT6_298>,
624 proof: Proof<MNT6_298>,
625 }
626
627 impl ConstraintSynthesizer<MNT6Fq> for Wrapper {
628 fn generate_constraints<CS: ConstraintSystem<MNT6Fq>>(
629 self,
630 cs: &mut CS,
631 ) -> Result<(), SynthesisError> {
632 let params = self.params;
633 let proof = self.proof;
634 let inputs: Vec<_> = self
635 .inputs
636 .into_iter()
637 .map(|input| input.unwrap())
638 .collect();
639 let input_gadgets;
640
641 {
642 let mut cs = cs.ns(|| "Allocate Input");
643 // Chain all input values in one large byte array.
644 let input_bytes = inputs
645 .clone()
646 .into_iter()
647 .flat_map(|input| {
648 input
649 .into_repr()
650 .as_ref()
651 .iter()
652 .flat_map(|l| l.to_le_bytes().to_vec())
653 .collect::<Vec<_>>()
654 })
655 .collect::<Vec<_>>();
656
657 // Allocate this byte array as input packed into field elements.
658 let input_bytes = UInt8::alloc_input_vec(cs.ns(|| "Input"), &input_bytes[..])?;
659 // 40 byte
660 let element_size = <MNT4FqParameters as FpParameters>::BigInt::NUM_LIMBS * 8;
661 input_gadgets = input_bytes
662 .chunks(element_size)
663 .map(|chunk| {
664 chunk
665 .iter()
666 .flat_map(|byte| byte.into_bits_le())
667 .collect::<Vec<_>>()
668 })
669 .collect::<Vec<_>>();
670 }
671
672 let vk_gadget = TestVkGadget1::alloc(cs.ns(|| "Vk"), || Ok(¶ms.vk))?;
673 let proof_gadget =
674 TestProofGadget1::alloc(cs.ns(|| "Proof"), || Ok(proof.clone())).unwrap();
675 <TestVerifierGadget1 as NIZKVerifierGadget<TestProofSystem1, MNT6Fq>>::check_verify(
676 cs.ns(|| "Verify"),
677 &vk_gadget,
678 input_gadgets.iter(),
679 &proof_gadget,
680 )?;
681 Ok(())
682 }
683 }
684
685 #[test]
686 fn groth16_recursive_verifier_test() {
687 let num_inputs = 100;
688 let num_constraints = num_inputs;
689 let rng = &mut test_rng();
690 let mut inputs: Vec<Option<MNT4Fq>> = Vec::with_capacity(num_inputs);
691 for _ in 0..num_inputs {
692 inputs.push(Some(rng.gen()));
693 }
694
695 // Generate inner params and proof.
696 let inner_params = {
697 let c = Bench::<MNT4Fq> {
698 inputs: vec![None; num_inputs],
699 num_constraints,
700 };
701
702 generate_random_parameters(c, rng).unwrap()
703 };
704
705 let inner_proof = {
706 // Create an instance of our circuit (with the
707 // witness)
708 let c = Bench {
709 inputs: inputs.clone(),
710 num_constraints,
711 };
712 // Create a groth16 proof with our parameters.
713 create_random_proof(c, &inner_params, rng).unwrap()
714 };
715
716 // Generate outer params and proof.
717 let params = {
718 let c = Wrapper {
719 inputs: inputs.clone(),
720 params: inner_params.clone(),
721 proof: inner_proof.clone(),
722 };
723
724 generate_random_parameters(c, rng).unwrap()
725 };
726
727 {
728 let proof = {
729 // Create an instance of our circuit (with the
730 // witness)
731 let c = Wrapper {
732 inputs: inputs.clone(),
733 params: inner_params.clone(),
734 proof: inner_proof.clone(),
735 };
736 // Create a groth16 proof with our parameters.
737 create_random_proof(c, ¶ms, rng).unwrap()
738 };
739
740 let mut cs = TestConstraintSystem::<MNT4Fq>::new();
741
742 let inputs: Vec<_> = inputs.into_iter().map(|input| input.unwrap()).collect();
743 let mut input_gadgets = Vec::new();
744
745 {
746 let bigint_size = <MNT4FqParameters as FpParameters>::BigInt::NUM_LIMBS * 64;
747 let mut input_bits = Vec::new();
748 let mut cs = cs.ns(|| "Allocate Input");
749 for (i, input) in inputs.into_iter().enumerate() {
750 let input_gadget =
751 FpGadget::alloc_input(cs.ns(|| format!("Input {}", i)), || Ok(input))
752 .unwrap();
753 let mut fp_bits = input_gadget
754 .to_bits(cs.ns(|| format!("To bits {}", i)))
755 .unwrap();
756
757 // FpGadget::to_bits outputs a big-endian binary representation of
758 // fe_gadget's value, so we have to reverse it to get the little-endian
759 // form.
760 fp_bits.reverse();
761
762 // Use 320 bits per element.
763 for _ in fp_bits.len()..bigint_size {
764 fp_bits.push(Boolean::constant(false));
765 }
766 input_bits.extend_from_slice(&fp_bits);
767 }
768
769 // Pack input bits into field elements of the underlying circuit.
770 let max_size = 8 * (<MNT6FqParameters as FpParameters>::CAPACITY / 8) as usize;
771 let max_size = max_size as usize;
772 let bigint_size = <MNT6FqParameters as FpParameters>::BigInt::NUM_LIMBS * 64;
773 for chunk in input_bits.chunks(max_size) {
774 let mut chunk = chunk.to_vec();
775 let len = chunk.len();
776 for _ in len..bigint_size {
777 chunk.push(Boolean::constant(false));
778 }
779 input_gadgets.push(chunk);
780 }
781 // assert!(!verify_proof(&pvk, &proof, &[a]).unwrap());
782 }
783
784 let vk_gadget = TestVkGadget2::alloc_input(cs.ns(|| "Vk"), || Ok(¶ms.vk)).unwrap();
785 let proof_gadget =
786 TestProofGadget2::alloc(cs.ns(|| "Proof"), || Ok(proof.clone())).unwrap();
787 println!("Time to verify!\n\n\n\n");
788 <TestVerifierGadget2 as NIZKVerifierGadget<TestProofSystem2, MNT4Fq>>::check_verify(
789 cs.ns(|| "Verify"),
790 &vk_gadget,
791 input_gadgets.iter(),
792 &proof_gadget,
793 )
794 .unwrap();
795 if !cs.is_satisfied() {
796 println!("=========================================================");
797 println!("Unsatisfied constraints:");
798 println!("{:?}", cs.which_is_unsatisfied().unwrap());
799 println!("=========================================================");
800 }
801
802 // cs.print_named_objects();
803 assert!(cs.is_satisfied());
804 }
805 }
806}