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