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