bellman/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 crate::{Circuit, ConstraintSystem, Index, LinearCombination, SynthesisError, Variable};
12
13use crate::domain::{EvaluationDomain, Scalar};
14
15use crate::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(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(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.0 {
111                match index {
112                    Variable(Index::Input(id)) => inputs[id].push((coeff, this_constraint)),
113                    Variable(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(|| "", |lc| lc + Variable(Index::Input(i)), |lc| lc, |lc| lc);
197    }
198
199    // Create bases for blind evaluation of polynomials at tau
200    let powers_of_tau = vec![Scalar::<E::Fr>(E::Fr::ZERO); assembly.num_constraints];
201    let mut powers_of_tau = EvaluationDomain::from_coeffs(powers_of_tau)?;
202
203    // Compute G1 window table
204    let mut g1_wnaf = Wnaf::new();
205    let g1_wnaf = g1_wnaf.base(g1, {
206        // H query
207        (powers_of_tau.as_ref().len() - 1)
208        // IC/L queries
209        + assembly.num_inputs + assembly.num_aux
210        // A query
211        + assembly.num_inputs + assembly.num_aux
212        // B query
213        + assembly.num_inputs + assembly.num_aux
214    });
215
216    // Compute G2 window table
217    let mut g2_wnaf = Wnaf::new();
218    let g2_wnaf = g2_wnaf.base(g2, {
219        // B query
220        assembly.num_inputs + assembly.num_aux
221    });
222
223    let gamma_inverse = {
224        let inverse = gamma.invert();
225        if bool::from(inverse.is_some()) {
226            Ok(inverse.unwrap())
227        } else {
228            Err(SynthesisError::UnexpectedIdentity)
229        }
230    }?;
231    let delta_inverse = {
232        let inverse = delta.invert();
233        if bool::from(inverse.is_some()) {
234            Ok(inverse.unwrap())
235        } else {
236            Err(SynthesisError::UnexpectedIdentity)
237        }
238    }?;
239
240    let worker = Worker::new();
241
242    let mut h = vec![E::G1Affine::identity(); powers_of_tau.as_ref().len() - 1];
243    {
244        // Compute powers of tau
245        {
246            let powers_of_tau = powers_of_tau.as_mut();
247            worker.scope(powers_of_tau.len(), |scope, chunk| {
248                for (i, powers_of_tau) in powers_of_tau.chunks_mut(chunk).enumerate() {
249                    scope.spawn(move |_scope| {
250                        let mut current_tau_power = tau.pow_vartime(&[(i * chunk) as u64]);
251
252                        for p in powers_of_tau {
253                            p.0 = current_tau_power;
254                            current_tau_power.mul_assign(&tau);
255                        }
256                    });
257                }
258            });
259        }
260
261        // coeff = t(x) / delta
262        let mut coeff = powers_of_tau.z(&tau);
263        coeff.mul_assign(&delta_inverse);
264
265        // Compute the H query with multiple threads
266        worker.scope(h.len(), |scope, chunk| {
267            for (h, p) in h
268                .chunks_mut(chunk)
269                .zip(powers_of_tau.as_ref().chunks(chunk))
270            {
271                let mut g1_wnaf = g1_wnaf.shared();
272
273                scope.spawn(move |_scope| {
274                    // Set values of the H query to g1^{(tau^i * t(tau)) / delta}
275                    let h_proj: Vec<_> = p[..h.len()]
276                        .iter()
277                        .map(|p| {
278                            // Compute final exponent
279                            let mut exp = p.0;
280                            exp.mul_assign(&coeff);
281
282                            // Exponentiate
283                            g1_wnaf.scalar(&exp)
284                        })
285                        .collect();
286
287                    // Batch normalize
288                    E::G1::batch_normalize(&h_proj, h);
289                });
290            }
291        });
292    }
293
294    // Use inverse FFT to convert powers of tau to Lagrange coefficients
295    powers_of_tau.ifft(&worker);
296    let powers_of_tau = powers_of_tau.into_coeffs();
297
298    let mut a = vec![E::G1Affine::identity(); assembly.num_inputs + assembly.num_aux];
299    let mut b_g1 = vec![E::G1Affine::identity(); assembly.num_inputs + assembly.num_aux];
300    let mut b_g2 = vec![E::G2Affine::identity(); assembly.num_inputs + assembly.num_aux];
301    let mut ic = vec![E::G1Affine::identity(); assembly.num_inputs];
302    let mut l = vec![E::G1Affine::identity(); assembly.num_aux];
303
304    #[allow(clippy::too_many_arguments)]
305    fn eval<E: Engine>(
306        // wNAF window tables
307        g1_wnaf: &Wnaf<usize, &[E::G1], &mut Vec<i64>>,
308        g2_wnaf: &Wnaf<usize, &[E::G2], &mut Vec<i64>>,
309
310        // Lagrange coefficients for tau
311        powers_of_tau: &[Scalar<E::Fr>],
312
313        // QAP polynomials
314        at: &[Vec<(E::Fr, usize)>],
315        bt: &[Vec<(E::Fr, usize)>],
316        ct: &[Vec<(E::Fr, usize)>],
317
318        // Resulting evaluated QAP polynomials
319        a: &mut [E::G1Affine],
320        b_g1: &mut [E::G1Affine],
321        b_g2: &mut [E::G2Affine],
322        ext: &mut [E::G1Affine],
323
324        // Inverse coefficient for ext elements
325        inv: &E::Fr,
326
327        // Trapdoors
328        alpha: &E::Fr,
329        beta: &E::Fr,
330
331        // Worker
332        worker: &Worker,
333    ) {
334        // Sanity check
335        assert_eq!(a.len(), at.len());
336        assert_eq!(a.len(), bt.len());
337        assert_eq!(a.len(), ct.len());
338        assert_eq!(a.len(), b_g1.len());
339        assert_eq!(a.len(), b_g2.len());
340        assert_eq!(a.len(), ext.len());
341
342        // Evaluate polynomials in multiple threads
343        worker.scope(a.len(), |scope, chunk| {
344            for ((((((a, b_g1), b_g2), ext), at), bt), ct) in a
345                .chunks_mut(chunk)
346                .zip(b_g1.chunks_mut(chunk))
347                .zip(b_g2.chunks_mut(chunk))
348                .zip(ext.chunks_mut(chunk))
349                .zip(at.chunks(chunk))
350                .zip(bt.chunks(chunk))
351                .zip(ct.chunks(chunk))
352            {
353                let mut g1_wnaf = g1_wnaf.shared();
354                let mut g2_wnaf = g2_wnaf.shared();
355
356                scope.spawn(move |_scope| {
357                    let mut a_proj = vec![E::G1::identity(); a.len()];
358                    let mut b_g1_proj = vec![E::G1::identity(); b_g1.len()];
359                    let mut b_g2_proj = vec![E::G2::identity(); b_g2.len()];
360                    let mut ext_proj = vec![E::G1::identity(); ext.len()];
361
362                    for ((((((a, b_g1), b_g2), ext), at), bt), ct) in a_proj
363                        .iter_mut()
364                        .zip(b_g1_proj.iter_mut())
365                        .zip(b_g2_proj.iter_mut())
366                        .zip(ext_proj.iter_mut())
367                        .zip(at.iter())
368                        .zip(bt.iter())
369                        .zip(ct.iter())
370                    {
371                        fn eval_at_tau<S: PrimeField>(
372                            powers_of_tau: &[Scalar<S>],
373                            p: &[(S, usize)],
374                        ) -> S {
375                            let mut acc = S::ZERO;
376
377                            for &(ref coeff, index) in p {
378                                let mut n = powers_of_tau[index].0;
379                                n.mul_assign(coeff);
380                                acc.add_assign(&n);
381                            }
382
383                            acc
384                        }
385
386                        // Evaluate QAP polynomials at tau
387                        let mut at = eval_at_tau(powers_of_tau, at);
388                        let mut bt = eval_at_tau(powers_of_tau, bt);
389                        let ct = eval_at_tau(powers_of_tau, ct);
390
391                        // Compute A query (in G1)
392                        if !at.is_zero_vartime() {
393                            *a = g1_wnaf.scalar(&at);
394                        }
395
396                        // Compute B query (in G1/G2)
397                        if !bt.is_zero_vartime() {
398                            *b_g1 = g1_wnaf.scalar(&bt);
399                            *b_g2 = g2_wnaf.scalar(&bt);
400                        }
401
402                        at *= beta;
403                        bt *= alpha;
404
405                        let mut e = at;
406                        e.add_assign(&bt);
407                        e.add_assign(&ct);
408                        e.mul_assign(inv);
409
410                        *ext = g1_wnaf.scalar(&e);
411                    }
412
413                    // Batch normalize
414                    E::G1::batch_normalize(&a_proj, a);
415                    E::G1::batch_normalize(&b_g1_proj, b_g1);
416                    E::G2::batch_normalize(&b_g2_proj, b_g2);
417                    E::G1::batch_normalize(&ext_proj, ext);
418                });
419            }
420        });
421    }
422
423    // Evaluate for inputs.
424    eval::<E>(
425        &g1_wnaf,
426        &g2_wnaf,
427        &powers_of_tau,
428        &assembly.at_inputs,
429        &assembly.bt_inputs,
430        &assembly.ct_inputs,
431        &mut a[0..assembly.num_inputs],
432        &mut b_g1[0..assembly.num_inputs],
433        &mut b_g2[0..assembly.num_inputs],
434        &mut ic,
435        &gamma_inverse,
436        &alpha,
437        &beta,
438        &worker,
439    );
440
441    // Evaluate for auxiliary variables.
442    eval::<E>(
443        &g1_wnaf,
444        &g2_wnaf,
445        &powers_of_tau,
446        &assembly.at_aux,
447        &assembly.bt_aux,
448        &assembly.ct_aux,
449        &mut a[assembly.num_inputs..],
450        &mut b_g1[assembly.num_inputs..],
451        &mut b_g2[assembly.num_inputs..],
452        &mut l,
453        &delta_inverse,
454        &alpha,
455        &beta,
456        &worker,
457    );
458
459    // Don't allow any elements be unconstrained, so that
460    // the L query is always fully dense.
461    for e in l.iter() {
462        if e.is_identity().into() {
463            return Err(SynthesisError::UnconstrainedVariable);
464        }
465    }
466
467    let g1 = g1.to_affine();
468    let g2 = g2.to_affine();
469
470    let vk = VerifyingKey::<E> {
471        alpha_g1: (g1 * alpha).to_affine(),
472        beta_g1: (g1 * beta).to_affine(),
473        beta_g2: (g2 * beta).to_affine(),
474        gamma_g2: (g2 * gamma).to_affine(),
475        delta_g1: (g1 * delta).to_affine(),
476        delta_g2: (g2 * delta).to_affine(),
477        ic,
478    };
479
480    Ok(Parameters {
481        vk,
482        h: Arc::new(h),
483        l: Arc::new(l),
484
485        // Filter points at infinity away from A/B queries
486        a: Arc::new(
487            a.into_iter()
488                .filter(|e| bool::from(!e.is_identity()))
489                .collect(),
490        ),
491        b_g1: Arc::new(
492            b_g1.into_iter()
493                .filter(|e| bool::from(!e.is_identity()))
494                .collect(),
495        ),
496        b_g2: Arc::new(
497            b_g2.into_iter()
498                .filter(|e| bool::from(!e.is_identity()))
499                .collect(),
500        ),
501    })
502}