groth16/
generator.rs

1use rand_core::RngCore;
2use std::ops::{AddAssign, MulAssign};
3use std::sync::Arc;
4
5use ff::{Field, PrimeField};
6use group::{prime::PrimeCurveAffine, Curve, Group, Wnaf, WnafGroup};
7use pairing::Engine;
8
9use super::{Parameters, VerifyingKey};
10
11use bellman::{Circuit, ConstraintSystem, Index, LinearCombination, SynthesisError, Variable};
12
13use bellman::domain::{EvaluationDomain, Scalar};
14
15use bellman::multicore::Worker;
16
17/// Generates a random common reference string for
18/// a circuit.
19pub fn generate_random_parameters<E, C, R>(
20    circuit: C,
21    mut rng: &mut R,
22) -> Result<Parameters<E>, SynthesisError>
23where
24    E: Engine,
25    E::G1: WnafGroup,
26    E::G2: WnafGroup,
27    C: Circuit<E::Fr>,
28    R: RngCore,
29{
30    let g1 = E::G1::random(&mut rng);
31    let g2 = E::G2::random(&mut rng);
32    let alpha = E::Fr::random(&mut rng);
33    let beta = E::Fr::random(&mut rng);
34    let gamma = E::Fr::random(&mut rng);
35    let delta = E::Fr::random(&mut rng);
36    let tau = E::Fr::random(&mut rng);
37
38    generate_parameters::<E, C>(circuit, g1, g2, alpha, beta, gamma, delta, tau)
39}
40
41/// This is our assembly structure that we'll use to synthesize the
42/// circuit into a QAP.
43struct KeypairAssembly<Scalar: PrimeField> {
44    num_inputs: usize,
45    num_aux: usize,
46    num_constraints: usize,
47    at_inputs: Vec<Vec<(Scalar, usize)>>,
48    bt_inputs: Vec<Vec<(Scalar, usize)>>,
49    ct_inputs: Vec<Vec<(Scalar, usize)>>,
50    at_aux: Vec<Vec<(Scalar, usize)>>,
51    bt_aux: Vec<Vec<(Scalar, usize)>>,
52    ct_aux: Vec<Vec<(Scalar, usize)>>,
53}
54
55impl<Scalar: PrimeField> ConstraintSystem<Scalar> for KeypairAssembly<Scalar> {
56    type Root = Self;
57
58    fn alloc<F, A, AR>(&mut self, _: A, _: F) -> Result<Variable, SynthesisError>
59    where
60        F: FnOnce() -> Result<Scalar, SynthesisError>,
61        A: FnOnce() -> AR,
62        AR: Into<String>,
63    {
64        // There is no assignment, so we don't even invoke the
65        // function for obtaining one.
66
67        let index = self.num_aux;
68        self.num_aux += 1;
69
70        self.at_aux.push(vec![]);
71        self.bt_aux.push(vec![]);
72        self.ct_aux.push(vec![]);
73
74        Ok(Variable::new_unchecked(Index::Aux(index)))
75    }
76
77    fn alloc_input<F, A, AR>(&mut self, _: A, _: F) -> Result<Variable, SynthesisError>
78    where
79        F: FnOnce() -> Result<Scalar, SynthesisError>,
80        A: FnOnce() -> AR,
81        AR: Into<String>,
82    {
83        // There is no assignment, so we don't even invoke the
84        // function for obtaining one.
85
86        let index = self.num_inputs;
87        self.num_inputs += 1;
88
89        self.at_inputs.push(vec![]);
90        self.bt_inputs.push(vec![]);
91        self.ct_inputs.push(vec![]);
92
93        Ok(Variable::new_unchecked(Index::Input(index)))
94    }
95
96    fn enforce<A, AR, LA, LB, LC>(&mut self, _: A, a: LA, b: LB, c: LC)
97    where
98        A: FnOnce() -> AR,
99        AR: Into<String>,
100        LA: FnOnce(LinearCombination<Scalar>) -> LinearCombination<Scalar>,
101        LB: FnOnce(LinearCombination<Scalar>) -> LinearCombination<Scalar>,
102        LC: FnOnce(LinearCombination<Scalar>) -> LinearCombination<Scalar>,
103    {
104        fn eval<Scalar: PrimeField>(
105            l: LinearCombination<Scalar>,
106            inputs: &mut [Vec<(Scalar, usize)>],
107            aux: &mut [Vec<(Scalar, usize)>],
108            this_constraint: usize,
109        ) {
110            for (index, coeff) in l.as_ref() {
111                match index.get_unchecked() {
112                    Index::Input(id) => inputs[id].push((*coeff, this_constraint)),
113                    Index::Aux(id) => aux[id].push((*coeff, this_constraint)),
114                }
115            }
116        }
117
118        eval(
119            a(LinearCombination::zero()),
120            &mut self.at_inputs,
121            &mut self.at_aux,
122            self.num_constraints,
123        );
124        eval(
125            b(LinearCombination::zero()),
126            &mut self.bt_inputs,
127            &mut self.bt_aux,
128            self.num_constraints,
129        );
130        eval(
131            c(LinearCombination::zero()),
132            &mut self.ct_inputs,
133            &mut self.ct_aux,
134            self.num_constraints,
135        );
136
137        self.num_constraints += 1;
138    }
139
140    fn push_namespace<NR, N>(&mut self, _: N)
141    where
142        NR: Into<String>,
143        N: FnOnce() -> NR,
144    {
145        // Do nothing; we don't care about namespaces in this context.
146    }
147
148    fn pop_namespace(&mut self) {
149        // Do nothing; we don't care about namespaces in this context.
150    }
151
152    fn get_root(&mut self) -> &mut Self::Root {
153        self
154    }
155}
156
157/// Create parameters for a circuit, given some toxic waste.
158#[allow(clippy::too_many_arguments)]
159pub fn generate_parameters<E, C>(
160    circuit: C,
161    g1: E::G1,
162    g2: E::G2,
163    alpha: E::Fr,
164    beta: E::Fr,
165    gamma: E::Fr,
166    delta: E::Fr,
167    tau: E::Fr,
168) -> Result<Parameters<E>, SynthesisError>
169where
170    E: Engine,
171    E::G1: WnafGroup,
172    E::G2: WnafGroup,
173    C: Circuit<E::Fr>,
174{
175    let mut assembly = KeypairAssembly {
176        num_inputs: 0,
177        num_aux: 0,
178        num_constraints: 0,
179        at_inputs: vec![],
180        bt_inputs: vec![],
181        ct_inputs: vec![],
182        at_aux: vec![],
183        bt_aux: vec![],
184        ct_aux: vec![],
185    };
186
187    // Allocate the "one" input variable
188    assembly.alloc_input(|| "", || Ok(E::Fr::ONE))?;
189
190    // Synthesize the circuit.
191    circuit.synthesize(&mut assembly)?;
192
193    // Input constraints to ensure full density of IC query
194    // x * 0 = 0
195    for i in 0..assembly.num_inputs {
196        assembly.enforce(
197            || "",
198            |lc| lc + Variable::new_unchecked(Index::Input(i)),
199            |lc| lc,
200            |lc| lc,
201        );
202    }
203
204    // Create bases for blind evaluation of polynomials at tau
205    let powers_of_tau = vec![Scalar::<E::Fr>(E::Fr::ZERO); assembly.num_constraints];
206    let mut powers_of_tau = EvaluationDomain::from_coeffs(powers_of_tau)?;
207
208    // Compute G1 window table
209    let mut g1_wnaf = Wnaf::new();
210    let g1_wnaf = g1_wnaf.base(g1, {
211        // H query
212        (powers_of_tau.as_ref().len() - 1)
213        // IC/L queries
214        + assembly.num_inputs + assembly.num_aux
215        // A query
216        + assembly.num_inputs + assembly.num_aux
217        // B query
218        + assembly.num_inputs + assembly.num_aux
219    });
220
221    // Compute G2 window table
222    let mut g2_wnaf = Wnaf::new();
223    let g2_wnaf = g2_wnaf.base(g2, {
224        // B query
225        assembly.num_inputs + assembly.num_aux
226    });
227
228    let gamma_inverse = {
229        let inverse = gamma.invert();
230        if bool::from(inverse.is_some()) {
231            Ok(inverse.unwrap())
232        } else {
233            Err(SynthesisError::UnexpectedIdentity)
234        }
235    }?;
236    let delta_inverse = {
237        let inverse = delta.invert();
238        if bool::from(inverse.is_some()) {
239            Ok(inverse.unwrap())
240        } else {
241            Err(SynthesisError::UnexpectedIdentity)
242        }
243    }?;
244
245    let worker = Worker::new();
246
247    let mut h = vec![E::G1Affine::identity(); powers_of_tau.as_ref().len() - 1];
248    {
249        // Compute powers of tau
250        {
251            let powers_of_tau = powers_of_tau.as_mut();
252            worker.scope(powers_of_tau.len(), |scope, chunk| {
253                for (i, powers_of_tau) in powers_of_tau.chunks_mut(chunk).enumerate() {
254                    scope.spawn(move |_scope| {
255                        let mut current_tau_power = tau.pow_vartime(&[(i * chunk) as u64]);
256
257                        for p in powers_of_tau {
258                            p.0 = current_tau_power;
259                            current_tau_power.mul_assign(&tau);
260                        }
261                    });
262                }
263            });
264        }
265
266        // coeff = t(x) / delta
267        let mut coeff = powers_of_tau.z(&tau);
268        coeff.mul_assign(&delta_inverse);
269
270        // Compute the H query with multiple threads
271        worker.scope(h.len(), |scope, chunk| {
272            for (h, p) in h
273                .chunks_mut(chunk)
274                .zip(powers_of_tau.as_ref().chunks(chunk))
275            {
276                let mut g1_wnaf = g1_wnaf.shared();
277
278                scope.spawn(move |_scope| {
279                    // Set values of the H query to g1^{(tau^i * t(tau)) / delta}
280                    let h_proj: Vec<_> = p[..h.len()]
281                        .iter()
282                        .map(|p| {
283                            // Compute final exponent
284                            let mut exp = p.0;
285                            exp.mul_assign(&coeff);
286
287                            // Exponentiate
288                            g1_wnaf.scalar(&exp)
289                        })
290                        .collect();
291
292                    // Batch normalize
293                    E::G1::batch_normalize(&h_proj, h);
294                });
295            }
296        });
297    }
298
299    // Use inverse FFT to convert powers of tau to Lagrange coefficients
300    powers_of_tau.ifft(&worker);
301    let powers_of_tau = powers_of_tau.into_coeffs();
302
303    let mut a = vec![E::G1Affine::identity(); assembly.num_inputs + assembly.num_aux];
304    let mut b_g1 = vec![E::G1Affine::identity(); assembly.num_inputs + assembly.num_aux];
305    let mut b_g2 = vec![E::G2Affine::identity(); assembly.num_inputs + assembly.num_aux];
306    let mut ic = vec![E::G1Affine::identity(); assembly.num_inputs];
307    let mut l = vec![E::G1Affine::identity(); assembly.num_aux];
308
309    #[allow(clippy::too_many_arguments)]
310    fn eval<E: Engine>(
311        // wNAF window tables
312        g1_wnaf: &Wnaf<usize, &[E::G1], &mut Vec<i64>>,
313        g2_wnaf: &Wnaf<usize, &[E::G2], &mut Vec<i64>>,
314
315        // Lagrange coefficients for tau
316        powers_of_tau: &[Scalar<E::Fr>],
317
318        // QAP polynomials
319        at: &[Vec<(E::Fr, usize)>],
320        bt: &[Vec<(E::Fr, usize)>],
321        ct: &[Vec<(E::Fr, usize)>],
322
323        // Resulting evaluated QAP polynomials
324        a: &mut [E::G1Affine],
325        b_g1: &mut [E::G1Affine],
326        b_g2: &mut [E::G2Affine],
327        ext: &mut [E::G1Affine],
328
329        // Inverse coefficient for ext elements
330        inv: &E::Fr,
331
332        // Trapdoors
333        alpha: &E::Fr,
334        beta: &E::Fr,
335
336        // Worker
337        worker: &Worker,
338    ) {
339        // Sanity check
340        assert_eq!(a.len(), at.len());
341        assert_eq!(a.len(), bt.len());
342        assert_eq!(a.len(), ct.len());
343        assert_eq!(a.len(), b_g1.len());
344        assert_eq!(a.len(), b_g2.len());
345        assert_eq!(a.len(), ext.len());
346
347        // Evaluate polynomials in multiple threads
348        worker.scope(a.len(), |scope, chunk| {
349            for ((((((a, b_g1), b_g2), ext), at), bt), ct) in a
350                .chunks_mut(chunk)
351                .zip(b_g1.chunks_mut(chunk))
352                .zip(b_g2.chunks_mut(chunk))
353                .zip(ext.chunks_mut(chunk))
354                .zip(at.chunks(chunk))
355                .zip(bt.chunks(chunk))
356                .zip(ct.chunks(chunk))
357            {
358                let mut g1_wnaf = g1_wnaf.shared();
359                let mut g2_wnaf = g2_wnaf.shared();
360
361                scope.spawn(move |_scope| {
362                    let mut a_proj = vec![E::G1::identity(); a.len()];
363                    let mut b_g1_proj = vec![E::G1::identity(); b_g1.len()];
364                    let mut b_g2_proj = vec![E::G2::identity(); b_g2.len()];
365                    let mut ext_proj = vec![E::G1::identity(); ext.len()];
366
367                    for ((((((a, b_g1), b_g2), ext), at), bt), ct) in a_proj
368                        .iter_mut()
369                        .zip(b_g1_proj.iter_mut())
370                        .zip(b_g2_proj.iter_mut())
371                        .zip(ext_proj.iter_mut())
372                        .zip(at.iter())
373                        .zip(bt.iter())
374                        .zip(ct.iter())
375                    {
376                        fn eval_at_tau<S: PrimeField>(
377                            powers_of_tau: &[Scalar<S>],
378                            p: &[(S, usize)],
379                        ) -> S {
380                            let mut acc = S::ZERO;
381
382                            for &(ref coeff, index) in p {
383                                let mut n = powers_of_tau[index].0;
384                                n.mul_assign(coeff);
385                                acc.add_assign(&n);
386                            }
387
388                            acc
389                        }
390
391                        // Evaluate QAP polynomials at tau
392                        let mut at = eval_at_tau(powers_of_tau, at);
393                        let mut bt = eval_at_tau(powers_of_tau, bt);
394                        let ct = eval_at_tau(powers_of_tau, ct);
395
396                        // Compute A query (in G1)
397                        if !at.is_zero_vartime() {
398                            *a = g1_wnaf.scalar(&at);
399                        }
400
401                        // Compute B query (in G1/G2)
402                        if !bt.is_zero_vartime() {
403                            *b_g1 = g1_wnaf.scalar(&bt);
404                            *b_g2 = g2_wnaf.scalar(&bt);
405                        }
406
407                        at *= beta;
408                        bt *= alpha;
409
410                        let mut e = at;
411                        e.add_assign(&bt);
412                        e.add_assign(&ct);
413                        e.mul_assign(inv);
414
415                        *ext = g1_wnaf.scalar(&e);
416                    }
417
418                    // Batch normalize
419                    E::G1::batch_normalize(&a_proj, a);
420                    E::G1::batch_normalize(&b_g1_proj, b_g1);
421                    E::G2::batch_normalize(&b_g2_proj, b_g2);
422                    E::G1::batch_normalize(&ext_proj, ext);
423                });
424            }
425        });
426    }
427
428    // Evaluate for inputs.
429    eval::<E>(
430        &g1_wnaf,
431        &g2_wnaf,
432        &powers_of_tau,
433        &assembly.at_inputs,
434        &assembly.bt_inputs,
435        &assembly.ct_inputs,
436        &mut a[0..assembly.num_inputs],
437        &mut b_g1[0..assembly.num_inputs],
438        &mut b_g2[0..assembly.num_inputs],
439        &mut ic,
440        &gamma_inverse,
441        &alpha,
442        &beta,
443        &worker,
444    );
445
446    // Evaluate for auxiliary variables.
447    eval::<E>(
448        &g1_wnaf,
449        &g2_wnaf,
450        &powers_of_tau,
451        &assembly.at_aux,
452        &assembly.bt_aux,
453        &assembly.ct_aux,
454        &mut a[assembly.num_inputs..],
455        &mut b_g1[assembly.num_inputs..],
456        &mut b_g2[assembly.num_inputs..],
457        &mut l,
458        &delta_inverse,
459        &alpha,
460        &beta,
461        &worker,
462    );
463
464    // Don't allow any elements be unconstrained, so that
465    // the L query is always fully dense.
466    for e in l.iter() {
467        if e.is_identity().into() {
468            return Err(SynthesisError::UnconstrainedVariable);
469        }
470    }
471
472    let g1 = g1.to_affine();
473    let g2 = g2.to_affine();
474
475    let vk = VerifyingKey::<E> {
476        alpha_g1: (g1 * alpha).to_affine(),
477        beta_g1: (g1 * beta).to_affine(),
478        beta_g2: (g2 * beta).to_affine(),
479        gamma_g2: (g2 * gamma).to_affine(),
480        delta_g1: (g1 * delta).to_affine(),
481        delta_g2: (g2 * delta).to_affine(),
482        ic,
483    };
484
485    Ok(Parameters {
486        vk,
487        h: Arc::new(h),
488        l: Arc::new(l),
489
490        // Filter points at infinity away from A/B queries
491        a: Arc::new(
492            a.into_iter()
493                .filter(|e| bool::from(!e.is_identity()))
494                .collect(),
495        ),
496        b_g1: Arc::new(
497            b_g1.into_iter()
498                .filter(|e| bool::from(!e.is_identity()))
499                .collect(),
500        ),
501        b_g2: Arc::new(
502            b_g2.into_iter()
503                .filter(|e| bool::from(!e.is_identity()))
504                .collect(),
505        ),
506    })
507}