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