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