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
17pub 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
41struct 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 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 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 }
147
148 fn pop_namespace(&mut self) {
149 }
151
152 fn get_root(&mut self) -> &mut Self::Root {
153 self
154 }
155}
156
157#[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 assembly.alloc_input(|| "", || Ok(E::Fr::ONE))?;
189
190 circuit.synthesize(&mut assembly)?;
192
193 for i in 0..assembly.num_inputs {
196 assembly.enforce(|| "", |lc| lc + Variable(Index::Input(i)), |lc| lc, |lc| lc);
197 }
198
199 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 let mut g1_wnaf = Wnaf::new();
205 let g1_wnaf = g1_wnaf.base(g1, {
206 (powers_of_tau.as_ref().len() - 1)
208 + assembly.num_inputs + assembly.num_aux
210 + assembly.num_inputs + assembly.num_aux
212 + assembly.num_inputs + assembly.num_aux
214 });
215
216 let mut g2_wnaf = Wnaf::new();
218 let g2_wnaf = g2_wnaf.base(g2, {
219 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 {
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 let mut coeff = powers_of_tau.z(&tau);
263 coeff.mul_assign(&delta_inverse);
264
265 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 let h_proj: Vec<_> = p[..h.len()]
276 .iter()
277 .map(|p| {
278 let mut exp = p.0;
280 exp.mul_assign(&coeff);
281
282 g1_wnaf.scalar(&exp)
284 })
285 .collect();
286
287 E::G1::batch_normalize(&h_proj, h);
289 });
290 }
291 });
292 }
293
294 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 g1_wnaf: &Wnaf<usize, &[E::G1], &mut Vec<i64>>,
308 g2_wnaf: &Wnaf<usize, &[E::G2], &mut Vec<i64>>,
309
310 powers_of_tau: &[Scalar<E::Fr>],
312
313 at: &[Vec<(E::Fr, usize)>],
315 bt: &[Vec<(E::Fr, usize)>],
316 ct: &[Vec<(E::Fr, usize)>],
317
318 a: &mut [E::G1Affine],
320 b_g1: &mut [E::G1Affine],
321 b_g2: &mut [E::G2Affine],
322 ext: &mut [E::G1Affine],
323
324 inv: &E::Fr,
326
327 alpha: &E::Fr,
329 beta: &E::Fr,
330
331 worker: &Worker,
333 ) {
334 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 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 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 if !at.is_zero_vartime() {
393 *a = g1_wnaf.scalar(&at);
394 }
395
396 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 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 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 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 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 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}