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