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