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