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