Clearmatics Libsnark  0.1
C++ library for zkSNARK proofs
bls12_377_precomputation.tcc
Go to the documentation of this file.
1 /** @file
2  *****************************************************************************
3  * @author This file is part of libsnark, developed by Clearmatics Ltd
4  * (originally developed by SCIPR Lab) and contributors
5  * (see AUTHORS).
6  * @copyright MIT license (see LICENSE file)
7  *****************************************************************************/
8 
9 #ifndef LIBSNARK_GADGETLIB1_GADGETS_PAIRING_BW6_761_BLS12_377_BLS12_377_PRECOMPUTATION_TCC_
10 #define LIBSNARK_GADGETLIB1_GADGETS_PAIRING_BW6_761_BLS12_377_BLS12_377_PRECOMPUTATION_TCC_
11 
12 namespace libsnark
13 {
14 
15 // Iterate through bits of loop_count, skipping the highest order bit.
16 
17 class bls12_377_miller_loop_bits
18 {
19 public:
20  inline bls12_377_miller_loop_bits()
21  {
22  // TODO: should not need to do this dynamically
23  ssize_t start_i = libff::bls12_377_ate_loop_count.max_bits();
24  while (!libff::bls12_377_ate_loop_count.test_bit(start_i--)) {
25  }
26  _i = start_i + 1;
27  }
28 
29  inline bool next()
30  {
31  if (_i > 0) {
32  --_i;
33  return true;
34  }
35 
36  return false;
37  }
38 
39  inline bool current() const
40  {
41  return libff::bls12_377_ate_loop_count.test_bit(_i);
42  }
43 
44  inline size_t index() const { return (size_t)_i; }
45 
46  inline bool last() const { return 0 == index(); }
47 
48 private:
49  ssize_t _i;
50 };
51 
52 // bls12_377_G1_precomputation methods
53 
54 template<typename ppT>
55 bls12_377_G1_precomputation<ppT>::bls12_377_G1_precomputation() : _Px(), _Py()
56 {
57 }
58 
59 template<typename ppT>
60 bls12_377_G1_precomputation<ppT>::bls12_377_G1_precomputation(
61  protoboard<FieldT> &pb,
62  const libff::G1<other_curve<ppT>> &P_val,
63  const std::string & /* annotation_prefix */)
64  : _Px(new pb_linear_combination<FieldT>())
65  , _Py(new pb_linear_combination<FieldT>())
66 {
67  libff::G1<other_curve<ppT>> P_affine = P_val;
68  P_affine.to_affine_coordinates();
69  _Px->assign(pb, P_affine.X);
70  _Py->assign(pb, P_affine.Y);
71  _Px->evaluate(pb);
72  _Py->evaluate(pb);
73 }
74 
75 // bls12_377_G2_proj methods
76 
77 template<typename ppT>
78 bls12_377_G2_proj<ppT>::bls12_377_G2_proj(
79  protoboard<libff::Fr<ppT>> &pb, const std::string &annotation_prefix)
80  : X(pb, FMT(annotation_prefix, " X"))
81  , Y(pb, FMT(annotation_prefix, " Y"))
82  , Z(pb, FMT(annotation_prefix, " Z"))
83 {
84 }
85 
86 template<typename ppT>
87 bls12_377_G2_proj<ppT>::bls12_377_G2_proj(
88  const Fqe_variable<ppT> &X_var,
89  const Fqe_variable<ppT> &Y_var,
90  const Fqe_variable<ppT> &Z_var)
91  : X(X_var), Y(Y_var), Z(Z_var)
92 {
93 }
94 
95 template<typename ppT>
96 void bls12_377_G2_proj<ppT>::generate_r1cs_witness(
97  const libff::bls12_377_G2 &element)
98 {
99  X.generate_r1cs_witness(element.X);
100  Y.generate_r1cs_witness(element.Y);
101  Z.generate_r1cs_witness(element.Z);
102 }
103 
104 // bls12_377_ate_ell_coeffs methods
105 
106 template<typename ppT>
107 bls12_377_ate_ell_coeffs<ppT>::bls12_377_ate_ell_coeffs(
108  protoboard<FqT> &pb, const std::string &annotation_prefix)
109  : ell_0(pb, FMT(annotation_prefix, " ell_0"))
110  , ell_vw(pb, FMT(annotation_prefix, " ell_vw"))
111  , ell_vv(pb, FMT(annotation_prefix, " ell_vv"))
112 {
113 }
114 
115 template<typename ppT>
116 bls12_377_ate_ell_coeffs<ppT>::bls12_377_ate_ell_coeffs(
117  protoboard<FqT> &pb,
118  const libff::Fqe<other_curve<ppT>> ell_0_val,
119  const libff::Fqe<other_curve<ppT>> ell_vw_val,
120  const libff::Fqe<other_curve<ppT>> ell_vv_val,
121  const std::string &annotation_prefix)
122  : ell_0(pb, ell_0_val, FMT(annotation_prefix, " ell_0"))
123  , ell_vw(pb, ell_vw_val, FMT(annotation_prefix, " ell_vw"))
124  , ell_vv(pb, ell_vv_val, FMT(annotation_prefix, " ell_vv"))
125 {
126 }
127 
128 // bls12_377_G2_precomputation methods
129 
130 template<typename ppT>
131 bls12_377_G2_precomputation<ppT>::bls12_377_G2_precomputation()
132 {
133 }
134 
135 template<typename ppT>
136 bls12_377_G2_precomputation<ppT>::bls12_377_G2_precomputation(
137  protoboard<FieldT> &pb,
138  const libff::G2<other_curve<ppT>> &Q_val,
139  const std::string &annotation_prefix)
140 {
141  const libff::G2_precomp<other_curve<ppT>> Q_prec =
142  other_curve<ppT>::precompute_G2(Q_val);
143  const size_t num_coeffs = Q_prec.coeffs.size();
144  _coeffs.reserve(num_coeffs);
145  for (size_t i = 0; i < num_coeffs; ++i) {
146  const libff::bls12_377_ate_ell_coeffs &c = Q_prec.coeffs[i];
147  _coeffs.emplace_back(new bls12_377_ate_ell_coeffs<ppT>(
148  pb,
149  c.ell_0,
150  c.ell_VW,
151  c.ell_VV,
152  FMT(annotation_prefix, " coeffs[%zu]", i)));
153  }
154 
155  assert(num_coeffs == _coeffs.size());
156 }
157 
158 // bls12_377_G1_precompute_gadget methods
159 
160 template<typename ppT>
161 bls12_377_G1_precompute_gadget<ppT>::bls12_377_G1_precompute_gadget(
162  protoboard<libff::Fr<ppT>> &pb,
163  const G1_variable<ppT> &P,
164  bls12_377_G1_precomputation<ppT> &P_prec,
165  const std::string &annotation_prefix)
166  : gadget<libff::Fr<ppT>>(pb, annotation_prefix)
167  , _Px(new pb_linear_combination<libff::Fr<ppT>>())
168  , _Py(new pb_linear_combination<libff::Fr<ppT>>())
169 {
170  // Ensure that we don't overwrite an existing precomputation.
171  assert(!P_prec._Px);
172  assert(!P_prec._Py);
173  _Px->assign(pb, P.X);
174  _Py->assign(pb, P.Y);
175  P_prec._Px = _Px;
176  P_prec._Py = _Py;
177 }
178 
179 template<typename ppT>
180 void bls12_377_G1_precompute_gadget<ppT>::generate_r1cs_constraints()
181 {
182 }
183 
184 template<typename ppT>
185 void bls12_377_G1_precompute_gadget<ppT>::generate_r1cs_witness()
186 {
187  _Px->evaluate(this->pb);
188  _Py->evaluate(this->pb);
189 }
190 
191 // bls12_377_ate_dbl_gadget methods
192 
193 template<typename ppT>
194 bls12_377_ate_dbl_gadget<ppT>::bls12_377_ate_dbl_gadget(
195  protoboard<FqT> &pb,
196  const bls12_377_G2_proj<ppT> &R,
197  const bls12_377_G2_proj<ppT> &out_R,
198  const bls12_377_ate_ell_coeffs<ppT> &coeffs,
199  const std::string &annotation_prefix)
200  : gadget<libff::Fr<ppT>>(pb, annotation_prefix)
201  , _in_R(R)
202  , _out_R(out_R)
203  , _out_coeffs(coeffs)
204 
205  // A = Rx * Ry / 2
206  , _compute_A(
207  pb,
208  _in_R.X,
209  _in_R.Y * FqT(2).inverse(),
210  Fqe_variable<ppT>(pb, FMT(annotation_prefix, " A")),
211  FMT(annotation_prefix, " _compute_A"))
212 
213  // B = Ry^2
214  , _compute_B(
215  pb,
216  _in_R.Y,
217  Fqe_variable<ppT>(pb, FMT(annotation_prefix, " B")),
218  FMT(annotation_prefix, " _compute_B"))
219 
220  // ell_0 = xi * I
221  // where
222  // C = Rz^2
223  // D = 3 * C
224  // E = b' * D
225  // I = (E - B)
226  // ell_0 = xi * I
227  // = xi * (E - B)
228  // = xi * (3*b'*C - B)
229  // = xi * (3*b'*Rz^2 - Ry^2)
230  // <=> Rz^2 [C] = (ell_0 + xi.Ry^2) / 3*b'*xi
231  // = (3*b')^{-1}(ell_0*xi^{-1} + B)
232  , _compute_C(
233  pb,
234  _in_R.Z,
235  (_out_coeffs.ell_0 * libff::bls12_377_twist.inverse() +
236  _compute_B.result) *
237  (FqT(3) * libff::bls12_377_twist_coeff_b).inverse(),
238  FMT(annotation_prefix, " _compute_C"))
239 
240  // D = 3 * C
241  // E = b' * D
242  // F = 3 * E
243 
244  // H = (Y + Z) ^ 2 - (B + C)
245  // ell_vw = -H
246  // = (B+C) - (Y+2)^2
247  // <=> (Y+2)^2 [H] = B + C - ell_vw
248  , _compute_Y_plus_Z_squared(
249  pb,
250  _in_R.Y + _in_R.Z,
251  _compute_B.result + _compute_C.result - _out_coeffs.ell_vw,
252  FMT(annotation_prefix, " _compute_Y_plus_Z_squared"))
253 
254  // I = (E - B)
255  // J = Rx^2
256  // ell_vv = 3 * J
257  // = 3 * Rx^2
258  // <=> Rx^2 [J] = ell_vv * 3^{-1}
259  , _compute_J(
260  pb,
261  _in_R.X,
262  _out_coeffs.ell_vv * FqT(3).inverse(),
263  FMT(annotation_prefix, " _compute_J"))
264 
265  // outRx = A * (B-F)
266  , _check_out_Rx(
267  pb,
268  _compute_A.result,
269  _compute_B.result - _compute_C.result *
270  libff::bls12_377_twist_coeff_b *
271  FqT(9), // B-F
272  _out_R.X,
273  FMT(annotation_prefix, " _check_out_Rx"))
274 
275  // outRy = G^2 - 3E^2
276  // where G = (B + F) / 2
277  // <=> G^2 = outRy + 3 * E^2
278  , _compute_E_squared(
279  pb,
280  _compute_C.result * libff::bls12_377_twist_coeff_b * FqT(3), // E
281  Fqe_variable<ppT>(pb, FMT(annotation_prefix, "E_squared")),
282  FMT(annotation_prefix, " _compute_E_squared"))
283  , _compute_G_squared(
284  pb,
285  (_compute_B.result +
286  _compute_C.result * libff::bls12_377_twist_coeff_b * FqT(9)) *
287  FqT(2).inverse(), // G = (B+F)/2
288  _out_R.Y + _compute_E_squared.result + _compute_E_squared.result +
289  _compute_E_squared.result,
290  FMT(annotation_prefix, " _compute_G_squared"))
291 
292  // outRz = B * H
293  // where
294  // H = (Y + Z)^2 - (B + C)
295  , _check_out_Rz(
296  pb,
297  _compute_B.result,
298  _compute_Y_plus_Z_squared.result - _compute_B.result -
299  _compute_C.result,
300  _out_R.Z,
301  FMT(annotation_prefix, " _check_out_Rz"))
302 {
303 }
304 
305 template<typename ppT>
306 void bls12_377_ate_dbl_gadget<ppT>::generate_r1cs_constraints()
307 {
308  _compute_A.generate_r1cs_constraints();
309  _compute_B.generate_r1cs_constraints();
310  _compute_C.generate_r1cs_constraints();
311  _compute_Y_plus_Z_squared.generate_r1cs_constraints();
312  _compute_J.generate_r1cs_constraints();
313  _check_out_Rx.generate_r1cs_constraints();
314  _compute_E_squared.generate_r1cs_constraints();
315  _compute_G_squared.generate_r1cs_constraints();
316  _check_out_Rz.generate_r1cs_constraints();
317 }
318 
319 template<typename ppT>
320 void bls12_377_ate_dbl_gadget<ppT>::generate_r1cs_witness()
321 {
322  const FqeT Rx = _in_R.X.get_element();
323  const FqeT Ry = _in_R.Y.get_element();
324  const FqeT Rz = _in_R.Z.get_element();
325 
326  // A = Rx * Ry / 2
327  _compute_A.B.evaluate();
328  _compute_A.generate_r1cs_witness();
329 
330  // B = Ry^2
331  _compute_B.generate_r1cs_witness();
332 
333  // ell_0 = xi * I
334  // where
335  // C = Rz^2
336  // D = 3 * C
337  // E = b' * D
338  // I = (E - B)
339  // <=> Rz^2 [C] = (ell_0.xi^{-1} + Ry^2) * (3*b')^{-1}
340  const FqeT B = _compute_B.result.get_element();
341  const FqeT C = Rz * Rz;
342  const FqeT D = FqT(3) * C;
343  const FqeT E = libff::bls12_377_twist_coeff_b * D;
344  const FqeT I = E - B;
345  _out_coeffs.ell_0.generate_r1cs_witness(libff::bls12_377_twist * I);
346  _compute_C.result.evaluate();
347  _compute_C.generate_r1cs_witness();
348  assert(C == _compute_C.result.get_element());
349  assert(
350  (_out_coeffs.ell_0.get_element() * libff::bls12_377_twist.inverse() +
351  B) *
352  (FqT(3) * libff::bls12_377_twist_coeff_b).inverse() ==
353  _compute_C.result.get_element());
354 
355  // G = (B + F) / 2
356  // ell_vw = -H
357  // where
358  // H = (Y + 2) ^ 2 - (B + C)
359  // ell_vw = (B+C) - (Y+2)^2
360  // <=> (Y+2)^2 [H] = ell_vw - B - C
361  const FqeT Ry_plus_Rz_squared = (Ry + Rz) * (Ry + Rz);
362  _out_coeffs.ell_vw.generate_r1cs_witness(B + C - Ry_plus_Rz_squared);
363  _compute_Y_plus_Z_squared.A.evaluate();
364  _compute_Y_plus_Z_squared.result.evaluate();
365  _compute_Y_plus_Z_squared.generate_r1cs_witness();
366  assert(
367  _compute_Y_plus_Z_squared.result.get_element() == Ry_plus_Rz_squared);
368 
369  // I = E - B
370 
371  // ell_vv = 3 * J
372  // J = Rx^2
373  const FqeT J = Rx * Rx;
374  _out_coeffs.ell_vv.generate_r1cs_witness(FqT(3) * J);
375  _compute_J.result.evaluate();
376  _compute_J.generate_r1cs_witness();
377 
378  // outRx = A * (B - F)
379  _check_out_Rx.B.evaluate();
380  _check_out_Rx.result.evaluate();
381  _check_out_Rx.generate_r1cs_witness();
382 
383  // outRy = G^2 - 3E^2
384  // where G = (B + F) / 2
385  // <=> G^2 = outRy + 3 * E^2
386  _compute_E_squared.A.evaluate();
387  _compute_E_squared.generate_r1cs_witness();
388  const FqeT E_squared = _compute_E_squared.result.get_element();
389  const FqeT F = FqT(3) * E;
390  const FqeT G = FqT(2).inverse() * (B + F);
391  const FqeT G_squared = G * G;
392  _out_R.Y.generate_r1cs_witness(G_squared - FqT(3) * E_squared);
393  _compute_G_squared.A.evaluate();
394  _compute_G_squared.result.evaluate();
395  _compute_G_squared.generate_r1cs_witness();
396 
397  // out_Rz = B * H (assigned by check_outRz)
398  _check_out_Rz.B.evaluate();
399  assert(B == _check_out_Rz.A.get_element());
400  assert(Ry_plus_Rz_squared - B - C == _check_out_Rz.B.get_element());
401  _check_out_Rz.generate_r1cs_witness();
402  assert(
403  B * (Ry_plus_Rz_squared - B - C) == _check_out_Rz.result.get_element());
404 }
405 
406 // bls12_377_ate_add_gadget methods
407 
408 template<typename ppT>
409 bls12_377_ate_add_gadget<ppT>::bls12_377_ate_add_gadget(
410  protoboard<libff::Fr<ppT>> &pb,
411  const Fqe_variable<ppT> &Q_X,
412  const Fqe_variable<ppT> &Q_Y,
413  const bls12_377_G2_proj<ppT> &in_R,
414  const bls12_377_G2_proj<ppT> &out_R,
415  const bls12_377_ate_ell_coeffs<ppT> &out_coeffs,
416  const std::string &annotation_prefix)
417  : gadget<libff::Fr<ppT>>(pb, annotation_prefix)
418  , _Q_X(Q_X)
419  , _Q_Y(Q_Y)
420  , _in_R(in_R)
421  , _out_R(out_R)
422  , _out_coeffs(out_coeffs)
423  // ell_vv = -theta
424  // where
425  // theta = Ry - A
426  // A = Qy * Rz;
427  // <=> A = Qy * Rz = ell_vv + Ry
428  , _compute_A(
429  pb,
430  _Q_Y,
431  _in_R.Z,
432  _out_coeffs.ell_vv + _in_R.Y,
433  FMT(annotation_prefix, " _compute_A"))
434  // ell_vw = lambda
435  // where
436  // lambda = Rx - B
437  // B = Qx * Rz
438  // <=> B = Qx * Rz = Rx - ell_vw
439  , _compute_B(
440  pb,
441  _Q_X,
442  _in_R.Z,
443  _in_R.X - _out_coeffs.ell_vw,
444  FMT(annotation_prefix, " _compute_B"))
445  // theta = Ry - A;
446  // , theta(in_R.Y + (A * -libff::Fr<ppT>::one()))
447  // lambda = Rx - B;
448  // , lambda(in_R.X + (B * -libff::Fr<ppT>::one()))
449  // C = theta.squared() = ell_vv^2
450  , _compute_C(
451  pb,
452  _out_coeffs.ell_vv,
453  Fqe_variable<ppT>(pb, FMT(annotation_prefix, " C")),
454  FMT(annotation_prefix, " _compute_C"))
455  // D = lambda.squared() = ell_vw^2
456  , _compute_D(
457  pb,
458  _out_coeffs.ell_vw,
459  Fqe_variable<ppT>(pb, FMT(annotation_prefix, " D")),
460  FMT(annotation_prefix, " _compute_D"))
461  // E = lambda * D = D * ell_vw;
462  , _compute_E(
463  pb,
464  _compute_D.result,
465  _out_coeffs.ell_vw,
466  Fqe_variable<ppT>(pb, FMT(annotation_prefix, " E")),
467  FMT(annotation_prefix, " _compute_E"))
468  // F = Rz * C;
469  , _compute_F(
470  pb,
471  _in_R.Z,
472  _compute_C.result,
473  Fqe_variable<ppT>(pb, FMT(annotation_prefix, " F")),
474  FMT(annotation_prefix, " _compute_F"))
475  // G = Rx * D;
476  , _compute_G(
477  pb,
478  _in_R.X,
479  _compute_D.result,
480  Fqe_variable<ppT>(pb, FMT(annotation_prefix, " G")),
481  FMT(annotation_prefix, " _compute_G"))
482  // H = E + F - (G + G);
483  , _H(_compute_E.result + _compute_F.result - _compute_G.result -
484  _compute_G.result)
485  // I = Ry * E;
486  , _compute_I(
487  pb,
488  _in_R.Y,
489  _compute_E.result,
490  Fqe_variable<ppT>(pb, FMT(annotation_prefix, " I")),
491  FMT(annotation_prefix, " _compute_I"))
492  // out_coeffs.ell_0 = xi * J
493  // where J = theta * Qx - lambda * Qy
494  // <=> lambda * Qy = theta * Qx - ell_0 * xi^{-1}
495  , _compute_theta_times_Qx(
496  pb,
497  -_out_coeffs.ell_vv,
498  _Q_X,
499  Fqe_variable<ppT>(pb, FMT(annotation_prefix, " theta_times_Qx")),
500  FMT(annotation_prefix, " _compute_theta_times_Qx"))
501  , _compute_lambda_times_Qy(
502  pb,
503  _out_coeffs.ell_vw,
504  _Q_Y,
505  _compute_theta_times_Qx.result -
506  (_out_coeffs.ell_0 * libff::bls12_377_twist.inverse()),
507  FMT(annotation_prefix, " _compute_lambda_times_Qy"))
508  // out_Rx = lambda * H = ell_vw * H
509  , _check_out_Rx(
510  pb,
511  _out_coeffs.ell_vw,
512  _H,
513  _out_R.X,
514  FMT(annotation_prefix, " _check_out_Rx"))
515  // out_Ry = theta * (G - H) - I = -ell_vv * (G-H) - I
516  // <=> ell_vv * (H-G) = out_Ry + I
517  , _check_out_Ry(
518  pb,
519  _out_coeffs.ell_vv,
520  _H - _compute_G.result,
521  _out_R.Y + _compute_I.result,
522  FMT(annotation_prefix, " _check_out_Ry"))
523  // out_Rz = Z1 * E;
524  , _check_out_Rz(
525  pb,
526  _in_R.Z,
527  _compute_E.result,
528  _out_R.Z,
529  FMT(annotation_prefix, " _check_out_Rz"))
530 {
531 }
532 
533 template<typename ppT>
534 void bls12_377_ate_add_gadget<ppT>::generate_r1cs_constraints()
535 {
536  _compute_A.generate_r1cs_constraints();
537  _compute_B.generate_r1cs_constraints();
538  _compute_C.generate_r1cs_constraints();
539  _compute_D.generate_r1cs_constraints();
540  _compute_E.generate_r1cs_constraints();
541  _compute_F.generate_r1cs_constraints();
542  _compute_G.generate_r1cs_constraints();
543  _compute_theta_times_Qx.generate_r1cs_constraints();
544  _compute_lambda_times_Qy.generate_r1cs_constraints();
545  _check_out_Rx.generate_r1cs_constraints();
546  _check_out_Ry.generate_r1cs_constraints();
547  _check_out_Rz.generate_r1cs_constraints();
548 }
549 
550 template<typename ppT>
551 void bls12_377_ate_add_gadget<ppT>::generate_r1cs_witness()
552 {
553  const FqeT Qx = _Q_X.get_element();
554  const FqeT Qy = _Q_Y.get_element();
555  const FqeT Rx = _in_R.X.get_element();
556  const FqeT Ry = _in_R.Y.get_element();
557  const FqeT Rz = _in_R.Z.get_element();
558 
559  // ell_vv = -theta
560  // where
561  // theta = Ry - A
562  // A = Qy * Rz;
563  // <=> A = Qy * Rz = ell_vv + Ry
564  const FqeT A = Qy * Rz;
565  const FqeT theta = Ry - A;
566  _out_coeffs.ell_vv.generate_r1cs_witness(-theta);
567  _compute_A.result.evaluate();
568  _compute_A.generate_r1cs_witness();
569 
570  // ell_vw = lambda
571  // where
572  // lambda = Rx - B
573  // B = Qx * Rz
574  // <=> B = Qx * Rz = Rx - ell_vw
575  const FqeT B = Qx * Rz;
576  const FqeT lambda = Rx - B;
577  _out_coeffs.ell_vw.generate_r1cs_witness(lambda);
578  _compute_B.result.evaluate();
579  _compute_B.generate_r1cs_witness();
580  // C = theta.squared() = ell_vv^2
581  _compute_C.generate_r1cs_witness();
582  // D = lambda.squared() = ell_vw^2
583  _compute_D.generate_r1cs_witness();
584  // E = lambda * D = D * ell_vw;
585  _compute_E.generate_r1cs_witness();
586  // F = Rz * C
587  _compute_F.generate_r1cs_witness();
588  // G = Rx * D;
589  _compute_G.generate_r1cs_witness();
590  // H = E + F - (G + G);
591  _H.evaluate();
592  // I = Ry * E
593  _compute_I.generate_r1cs_witness();
594  // out_coeffs.ell_0 = xi * J
595  // where J = theta * Qx - lambda * Qy
596  // <=> lambda * Qy = theta * Qx - ell_0 * xi^{-1}
597  _compute_theta_times_Qx.A.evaluate();
598  _compute_theta_times_Qx.generate_r1cs_witness();
599  const FqeT theta_times_Qx = _compute_theta_times_Qx.result.get_element();
600  const FqeT lambda_times_Qy = lambda * Qy;
601  _out_coeffs.ell_0.generate_r1cs_witness(
602  libff::bls12_377_twist * (theta_times_Qx - lambda_times_Qy));
603  _compute_lambda_times_Qy.result.evaluate();
604  _compute_lambda_times_Qy.generate_r1cs_witness();
605  // out_Rx = lambda * H = ell_vw * H
606  _check_out_Rx.generate_r1cs_witness();
607  // out_Ry = theta * (G - H) - I = -ell_vv * (G-H) - I
608  // <=> ell_vv * (H-G) = out_Ry + I
609  const FqeT G = _compute_G.result.get_element();
610  const FqeT H = _H.get_element();
611  const FqeT I = _compute_I.result.get_element();
612  _out_R.Y.generate_r1cs_witness(theta * (G - H) - I);
613  _check_out_Ry.B.evaluate();
614  _check_out_Ry.result.evaluate();
615  _check_out_Ry.generate_r1cs_witness();
616  // out_Rz = Z1 * E
617  _check_out_Rz.generate_r1cs_witness();
618 }
619 
620 // bls12_377_G2_precompute methods
621 
622 template<typename ppT>
623 bls12_377_G2_precompute_gadget<ppT>::bls12_377_G2_precompute_gadget(
624  protoboard<libff::Fr<ppT>> &pb,
625  const G2_variable<ppT> &Q,
626  bls12_377_G2_precomputation<ppT> &Q_prec,
627  const std::string &annotation_prefix)
628  : gadget<libff::Fr<ppT>>(pb, annotation_prefix)
629  , _R0(*Q.X, *Q.Y, Fqe_variable<ppT>(pb, FqeT::one(), "Fqe(1)"))
630 {
631  // Track the R variable at each step. Initially it is _R0;
632  const bls12_377_G2_proj<ppT> *currentR = &_R0;
633  size_t num_dbl = 0;
634  size_t num_add = 0;
635  size_t num_Rs = 0;
636  std::vector<std::shared_ptr<bls12_377_G2_proj<ppT>>> R;
637 
638  // Iterate through bits of loop_count
639  bls12_377_miller_loop_bits bits;
640  while (bits.next()) {
641  R.push_back(
642  std::shared_ptr<bls12_377_G2_proj<ppT>>(new bls12_377_G2_proj<ppT>(
643  pb, FMT(annotation_prefix, " R%zu", num_Rs++))));
644  Q_prec._coeffs.push_back(std::shared_ptr<bls12_377_ate_ell_coeffs<ppT>>(
645  new bls12_377_ate_ell_coeffs<ppT>(
646  pb, FMT(annotation_prefix, " Q_prec_dbl_%zu", num_dbl++))));
647  _ate_dbls.push_back(std::shared_ptr<bls12_377_ate_dbl_gadget<ppT>>(
648  new bls12_377_ate_dbl_gadget<ppT>(
649  pb,
650  *currentR,
651  *R.back(),
652  *Q_prec._coeffs.back(),
653  FMT(annotation_prefix, " dbls[%zu]", bits.index()))));
654  currentR = &(*R.back());
655 
656  if (bits.current()) {
657  R.push_back(std::shared_ptr<bls12_377_G2_proj<ppT>>(
658  new bls12_377_G2_proj<ppT>(
659  pb, FMT(annotation_prefix, " R%zu", num_Rs++))));
660  Q_prec._coeffs.push_back(
661  std::shared_ptr<bls12_377_ate_ell_coeffs<ppT>>(
662  new bls12_377_ate_ell_coeffs<ppT>(
663  pb,
664  FMT(annotation_prefix, " Q_prec_add_%zu", num_add++))));
665  _ate_adds.push_back(std::shared_ptr<bls12_377_ate_add_gadget<ppT>>(
666  new bls12_377_ate_add_gadget<ppT>(
667  pb,
668  *Q.X,
669  *Q.Y,
670  *currentR,
671  *R.back(),
672  *Q_prec._coeffs.back(),
673  FMT(annotation_prefix, " adds[%zu]", bits.index()))));
674  currentR = &(*R.back());
675  }
676  }
677 }
678 
679 template<typename ppT>
680 void bls12_377_G2_precompute_gadget<ppT>::generate_r1cs_constraints()
681 {
682  size_t dbl_idx = 0;
683  size_t add_idx = 0;
684 
685  // TODO: There should be no need to loop through the bits of loop_count
686  // when generating the constraints (all variables have been allocated, so
687  // the order of generation is not important). For now we do
688  // this to keep a
689  // consistent loop in all methods.
690 
691  bls12_377_miller_loop_bits bits;
692  while (bits.next()) {
693  _ate_dbls[dbl_idx++]->generate_r1cs_constraints();
694  if (bits.current()) {
695  _ate_adds[add_idx++]->generate_r1cs_constraints();
696  }
697  }
698 }
699 
700 template<typename ppT>
701 void bls12_377_G2_precompute_gadget<ppT>::generate_r1cs_witness()
702 {
703  size_t dbl_idx = 0;
704  size_t add_idx = 0;
705  bls12_377_miller_loop_bits bits;
706  while (bits.next()) {
707  _ate_dbls[dbl_idx++]->generate_r1cs_witness();
708  if (bits.current()) {
709  _ate_adds[add_idx++]->generate_r1cs_witness();
710  }
711  }
712 }
713 
714 } // namespace libsnark
715 
716 #endif // LIBSNARK_GADGETLIB1_GADGETS_PAIRING_BW6_761_BLS12_377_BLS12_377_PRECOMPUTATION_TCC_