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