arnaucube
arnaucube/ark-r1cs-stdPublic Self-hosted repository
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, &params, 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(&params.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(&params.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, &params, 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(&params.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}