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