Clearmatics Libsnark  0.1
C++ library for zkSNARK proofs
mnt_miller_loop.tcc
Go to the documentation of this file.
1 /** @file
2  *****************************************************************************
3 
4  Implementation of interfaces for gadgets for Miller loops.
5 
6  See weierstrass_miller_loop.hpp .
7 
8  *****************************************************************************
9  * @author This file is part of libsnark, developed by SCIPR Lab
10  * and contributors (see AUTHORS).
11  * @copyright MIT license (see LICENSE file)
12  *****************************************************************************/
13 
14 #ifndef LIBSNARK_GADGETLIB1_GADGETS_PAIRING_MNT_MNT_MILLER_LOOP_TCC_
15 #define LIBSNARK_GADGETLIB1_GADGETS_PAIRING_MNT_MNT_MILLER_LOOP_TCC_
16 
17 #include "libsnark/gadgetlib1/constraint_profiling.hpp"
18 #include "libsnark/gadgetlib1/gadgets/basic_gadgets.hpp"
19 #include "libsnark/gadgetlib1/gadgets/pairing/mnt/mnt_miller_loop.hpp"
20 
21 #include <libff/algebra/scalar_multiplication/wnaf.hpp>
22 
23 namespace libsnark
24 {
25 
26 /*
27  performs
28 
29  mnt_Fqk g_RR_at_P = mnt_Fqk(prec_P.PY_twist_squared,
30  -prec_P.PX * c.gamma_twist + c.gamma_X - c.old_RY);
31 
32  (later in Miller loop: f = f.squared() * g_RR_at_P)
33 */
34 
35 /* Note the slight interface change: this gadget will allocate g_RR_at_P inside
36  * itself (!) */
37 template<typename ppT>
38 mnt_miller_loop_dbl_line_eval<ppT>::mnt_miller_loop_dbl_line_eval(
39  protoboard<FieldT> &pb,
40  const mnt_G1_precomputation<ppT> &prec_P,
41  const mnt_precompute_G2_gadget_coeffs<ppT> &c,
42  std::shared_ptr<Fqk_variable<ppT>> &g_RR_at_P,
43  const std::string &annotation_prefix)
44  : gadget<FieldT>(pb, annotation_prefix)
45  , prec_P(prec_P)
46  , c(c)
47  , g_RR_at_P(g_RR_at_P)
48 {
49  gamma_twist.reset(new Fqe_variable<ppT>(c.gamma->mul_by_X()));
50  // prec_P.PX * c.gamma_twist = c.gamma_X - c.old_RY - g_RR_at_P_c1
51  if (gamma_twist->is_constant()) {
52  gamma_twist->evaluate();
53  const FqeT gamma_twist_const = gamma_twist->get_element();
54  g_RR_at_P_c1.reset(new Fqe_variable<ppT>(
55  Fqe_variable<ppT>(
56  this->pb,
57  -gamma_twist_const,
58  prec_P.P->X,
59  FMT(annotation_prefix, " tmp")) +
60  *(c.gamma_X) + *(c.RY) * (-FieldT::one())));
61  } else if (prec_P.P->X.is_constant()) {
62  prec_P.P->X.evaluate(pb);
63  const FieldT P_X_const = prec_P.P->X.constant_term();
64  g_RR_at_P_c1.reset(new Fqe_variable<ppT>(
65  *gamma_twist * (-P_X_const) + *(c.gamma_X) +
66  *(c.RY) * (-FieldT::one())));
67  } else {
68  g_RR_at_P_c1.reset(
69  new Fqe_variable<ppT>(pb, FMT(annotation_prefix, " g_RR_at_P_c1")));
70  compute_g_RR_at_P_c1.reset(new Fqe_mul_by_lc_gadget<ppT>(
71  pb,
72  *gamma_twist,
73  prec_P.P->X,
74  *(c.gamma_X) + *(c.RY) * (-FieldT::one()) +
75  (*g_RR_at_P_c1) * (-FieldT::one()),
76  FMT(annotation_prefix, " compute_g_RR_at_P_c1")));
77  }
78  g_RR_at_P.reset(new Fqk_variable<ppT>(
79  pb,
80  *(prec_P.PY_twist_squared),
81  *g_RR_at_P_c1,
82  FMT(annotation_prefix, " g_RR_at_P")));
83 }
84 
85 template<typename ppT>
86 void mnt_miller_loop_dbl_line_eval<ppT>::generate_r1cs_constraints()
87 {
88  if (!gamma_twist->is_constant() && !prec_P.P->X.is_constant()) {
89  compute_g_RR_at_P_c1->generate_r1cs_constraints();
90  }
91 }
92 
93 template<typename ppT>
94 void mnt_miller_loop_dbl_line_eval<ppT>::generate_r1cs_witness()
95 {
96  gamma_twist->evaluate();
97  const FqeT gamma_twist_val = gamma_twist->get_element();
98  const FieldT PX_val = this->pb.lc_val(prec_P.P->X);
99  const FqeT gamma_X_val = c.gamma_X->get_element();
100  const FqeT RY_val = c.RY->get_element();
101  const FqeT g_RR_at_P_c1_val =
102  -PX_val * gamma_twist_val + gamma_X_val - RY_val;
103  g_RR_at_P_c1->generate_r1cs_witness(g_RR_at_P_c1_val);
104 
105  if (!gamma_twist->is_constant() && !prec_P.P->X.is_constant()) {
106  compute_g_RR_at_P_c1->generate_r1cs_witness();
107  }
108  g_RR_at_P->evaluate();
109 }
110 
111 /*
112  performs
113  mnt_Fqk g_RQ_at_P = mnt_Fqk(prec_P.PY_twist_squared,
114  -prec_P.PX * c.gamma_twist + c.gamma_X - prec_Q.QY);
115 
116  (later in Miller loop: f = f * g_RQ_at_P)
117 
118  If invert_Q is set to true: use -QY in place of QY everywhere above.
119 */
120 
121 /* Note the slight interface change: this gadget will allocate g_RQ_at_P inside
122  * itself (!) */
123 template<typename ppT>
124 mnt_miller_loop_add_line_eval<ppT>::mnt_miller_loop_add_line_eval(
125  protoboard<FieldT> &pb,
126  const bool invert_Q,
127  const mnt_G1_precomputation<ppT> &prec_P,
128  const mnt_precompute_G2_gadget_coeffs<ppT> &c,
129  const G2_variable<ppT> &Q,
130  std::shared_ptr<Fqk_variable<ppT>> &g_RQ_at_P,
131  const std::string &annotation_prefix)
132  : gadget<FieldT>(pb, annotation_prefix)
133  , invert_Q(invert_Q)
134  , prec_P(prec_P)
135  , c(c)
136  , Q(Q)
137  , g_RQ_at_P(g_RQ_at_P)
138 {
139  gamma_twist.reset(new Fqe_variable<ppT>(c.gamma->mul_by_X()));
140  // prec_P.PX * c.gamma_twist = c.gamma_X - prec_Q.QY - g_RQ_at_P_c1
141  if (gamma_twist->is_constant()) {
142  gamma_twist->evaluate();
143  const FqeT gamma_twist_const = gamma_twist->get_element();
144  g_RQ_at_P_c1.reset(new Fqe_variable<ppT>(
145  Fqe_variable<ppT>(
146  this->pb,
147  -gamma_twist_const,
148  prec_P.P->X,
149  FMT(annotation_prefix, " tmp")) +
150  *(c.gamma_X) +
151  *(Q.Y) * (!invert_Q ? -FieldT::one() : FieldT::one())));
152  } else if (prec_P.P->X.is_constant()) {
153  prec_P.P->X.evaluate(pb);
154  const FieldT P_X_const = prec_P.P->X.constant_term();
155  g_RQ_at_P_c1.reset(new Fqe_variable<ppT>(
156  *gamma_twist * (-P_X_const) + *(c.gamma_X) +
157  *(Q.Y) * (!invert_Q ? -FieldT::one() : FieldT::one())));
158  } else {
159  g_RQ_at_P_c1.reset(
160  new Fqe_variable<ppT>(pb, FMT(annotation_prefix, " g_RQ_at_Q_c1")));
161  compute_g_RQ_at_P_c1.reset(new Fqe_mul_by_lc_gadget<ppT>(
162  pb,
163  *gamma_twist,
164  prec_P.P->X,
165  *(c.gamma_X) +
166  *(Q.Y) * (!invert_Q ? -FieldT::one() : FieldT::one()) +
167  (*g_RQ_at_P_c1) * (-FieldT::one()),
168  FMT(annotation_prefix, " compute_g_RQ_at_P_c1")));
169  }
170  g_RQ_at_P.reset(new Fqk_variable<ppT>(
171  pb,
172  *(prec_P.PY_twist_squared),
173  *g_RQ_at_P_c1,
174  FMT(annotation_prefix, " g_RQ_at_P")));
175 }
176 
177 template<typename ppT>
178 void mnt_miller_loop_add_line_eval<ppT>::generate_r1cs_constraints()
179 {
180  if (!gamma_twist->is_constant() && !prec_P.P->X.is_constant()) {
181  compute_g_RQ_at_P_c1->generate_r1cs_constraints();
182  }
183 }
184 
185 template<typename ppT>
186 void mnt_miller_loop_add_line_eval<ppT>::generate_r1cs_witness()
187 {
188  gamma_twist->evaluate();
189  const FqeT gamma_twist_val = gamma_twist->get_element();
190  const FieldT PX_val = this->pb.lc_val(prec_P.P->X);
191  const FqeT gamma_X_val = c.gamma_X->get_element();
192  const FqeT QY_val = Q.Y->get_element();
193  const FqeT g_RQ_at_P_c1_val = -PX_val * gamma_twist_val + gamma_X_val +
194  (!invert_Q ? -QY_val : QY_val);
195  g_RQ_at_P_c1->generate_r1cs_witness(g_RQ_at_P_c1_val);
196 
197  if (!gamma_twist->is_constant() && !prec_P.P->X.is_constant()) {
198  compute_g_RQ_at_P_c1->generate_r1cs_witness();
199  }
200  g_RQ_at_P->evaluate();
201 }
202 
203 template<typename ppT>
204 mnt_miller_loop_gadget<ppT>::mnt_miller_loop_gadget(
205  protoboard<FieldT> &pb,
206  const mnt_G1_precomputation<ppT> &prec_P,
207  const mnt_G2_precomputation<ppT> &prec_Q,
208  const Fqk_variable<ppT> &result,
209  const std::string &annotation_prefix)
210  : gadget<FieldT>(pb, annotation_prefix)
211  , prec_P(prec_P)
212  , prec_Q(prec_Q)
213  , result(result)
214 {
215  const auto &loop_count = mnt_pairing_params<ppT>::pairing_loop_count;
216 
217  f_count = add_count = dbl_count = 0;
218 
219  bool found_nonzero = false;
220  std::vector<long> NAF = find_wnaf(1, loop_count);
221  for (long i = NAF.size() - 1; i >= 0; --i) {
222  if (!found_nonzero) {
223  /* this skips the MSB itself */
224  found_nonzero |= (NAF[i] != 0);
225  continue;
226  }
227 
228  ++dbl_count;
229  f_count += 2;
230 
231  if (NAF[i] != 0) {
232  ++add_count;
233  f_count += 1;
234  }
235  }
236 
237  fs.resize(f_count);
238  doubling_steps.resize(dbl_count);
239  addition_steps.resize(add_count);
240  g_RR_at_Ps.resize(dbl_count);
241  g_RQ_at_Ps.resize(add_count);
242 
243  for (size_t i = 0; i < f_count; ++i) {
244  fs[i].reset(
245  new Fqk_variable<ppT>(pb, FMT(annotation_prefix, " fs_%zu", i)));
246  }
247 
248  dbl_sqrs.resize(dbl_count);
249  dbl_muls.resize(dbl_count);
250  add_muls.resize(add_count);
251 
252  size_t add_id = 0;
253  size_t dbl_id = 0;
254  size_t f_id = 0;
255  size_t prec_id = 0;
256 
257  found_nonzero = false;
258  for (long i = NAF.size() - 1; i >= 0; --i) {
259  if (!found_nonzero) {
260  /* this skips the MSB itself */
261  found_nonzero |= (NAF[i] != 0);
262  continue;
263  }
264 
265  doubling_steps[dbl_id].reset(new mnt_miller_loop_dbl_line_eval<ppT>(
266  pb,
267  prec_P,
268  *prec_Q.coeffs[prec_id],
269  g_RR_at_Ps[dbl_id],
270  FMT(annotation_prefix, " doubling_steps_%zu", dbl_id)));
271  ++prec_id;
272  dbl_sqrs[dbl_id].reset(new Fqk_sqr_gadget<ppT>(
273  pb,
274  *fs[f_id],
275  *fs[f_id + 1],
276  FMT(annotation_prefix, " dbl_sqrs_%zu", dbl_id)));
277  ++f_id;
278  dbl_muls[dbl_id].reset(new Fqk_special_mul_gadget(
279  pb,
280  *fs[f_id],
281  *g_RR_at_Ps[dbl_id],
282  (f_id + 1 == f_count ? result : *fs[f_id + 1]),
283  FMT(annotation_prefix, " dbl_muls_%zu", dbl_id)));
284  ++f_id;
285  ++dbl_id;
286 
287  if (NAF[i] != 0) {
288  addition_steps[add_id].reset(new mnt_miller_loop_add_line_eval<ppT>(
289  pb,
290  NAF[i] < 0,
291  prec_P,
292  *prec_Q.coeffs[prec_id],
293  *prec_Q.Q,
294  g_RQ_at_Ps[add_id],
295  FMT(annotation_prefix, " addition_steps_%zu", add_id)));
296  ++prec_id;
297  add_muls[add_id].reset(new Fqk_special_mul_gadget(
298  pb,
299  *fs[f_id],
300  *g_RQ_at_Ps[add_id],
301  (f_id + 1 == f_count ? result : *fs[f_id + 1]),
302  FMT(annotation_prefix, " add_muls_%zu", add_id)));
303  ++f_id;
304  ++add_id;
305  }
306  }
307 }
308 
309 template<typename ppT>
310 void mnt_miller_loop_gadget<ppT>::generate_r1cs_constraints()
311 {
312  fs[0]->generate_r1cs_equals_const_constraints(FqkT::one());
313 
314  for (size_t i = 0; i < dbl_count; ++i) {
315  doubling_steps[i]->generate_r1cs_constraints();
316  dbl_sqrs[i]->generate_r1cs_constraints();
317  dbl_muls[i]->generate_r1cs_constraints();
318  }
319 
320  for (size_t i = 0; i < add_count; ++i) {
321  addition_steps[i]->generate_r1cs_constraints();
322  add_muls[i]->generate_r1cs_constraints();
323  }
324 }
325 
326 template<typename ppT> void mnt_miller_loop_gadget<ppT>::generate_r1cs_witness()
327 {
328  fs[0]->generate_r1cs_witness(FqkT::one());
329 
330  size_t add_id = 0;
331  size_t dbl_id = 0;
332 
333  const auto &loop_count = mnt_pairing_params<ppT>::pairing_loop_count;
334 
335  bool found_nonzero = false;
336  std::vector<long> NAF = find_wnaf(1, loop_count);
337  for (long i = NAF.size() - 1; i >= 0; --i) {
338  if (!found_nonzero) {
339  /* this skips the MSB itself */
340  found_nonzero |= (NAF[i] != 0);
341  continue;
342  }
343 
344  doubling_steps[dbl_id]->generate_r1cs_witness();
345  dbl_sqrs[dbl_id]->generate_r1cs_witness();
346  dbl_muls[dbl_id]->generate_r1cs_witness();
347  ++dbl_id;
348 
349  if (NAF[i] != 0) {
350  addition_steps[add_id]->generate_r1cs_witness();
351  add_muls[add_id]->generate_r1cs_witness();
352  ++add_id;
353  }
354  }
355 }
356 
357 template<typename ppT>
358 mnt_e_over_e_miller_loop_gadget<ppT>::mnt_e_over_e_miller_loop_gadget(
359  protoboard<FieldT> &pb,
360  const mnt_G1_precomputation<ppT> &prec_P1,
361  const mnt_G2_precomputation<ppT> &prec_Q1,
362  const mnt_G1_precomputation<ppT> &prec_P2,
363  const mnt_G2_precomputation<ppT> &prec_Q2,
364  const Fqk_variable<ppT> &result,
365  const std::string &annotation_prefix)
366  : gadget<FieldT>(pb, annotation_prefix)
367  , prec_P1(prec_P1)
368  , prec_Q1(prec_Q1)
369  , prec_P2(prec_P2)
370  , prec_Q2(prec_Q2)
371  , result(result)
372 {
373  const auto &loop_count = mnt_pairing_params<ppT>::pairing_loop_count;
374 
375  f_count = add_count = dbl_count = 0;
376 
377  bool found_nonzero = false;
378  std::vector<long> NAF = find_wnaf(1, loop_count);
379  for (long i = NAF.size() - 1; i >= 0; --i) {
380  if (!found_nonzero) {
381  /* this skips the MSB itself */
382  found_nonzero |= (NAF[i] != 0);
383  continue;
384  }
385 
386  ++dbl_count;
387  f_count += 3;
388 
389  if (NAF[i] != 0) {
390  ++add_count;
391  f_count += 2;
392  }
393  }
394 
395  fs.resize(f_count);
396  doubling_steps1.resize(dbl_count);
397  addition_steps1.resize(add_count);
398  doubling_steps2.resize(dbl_count);
399  addition_steps2.resize(add_count);
400  g_RR_at_P1s.resize(dbl_count);
401  g_RQ_at_P1s.resize(add_count);
402  g_RR_at_P2s.resize(dbl_count);
403  g_RQ_at_P2s.resize(add_count);
404 
405  for (size_t i = 0; i < f_count; ++i) {
406  fs[i].reset(
407  new Fqk_variable<ppT>(pb, FMT(annotation_prefix, " fs_%zu", i)));
408  }
409 
410  dbl_sqrs.resize(dbl_count);
411  dbl_muls1.resize(dbl_count);
412  add_muls1.resize(add_count);
413  dbl_muls2.resize(dbl_count);
414  add_muls2.resize(add_count);
415 
416  size_t add_id = 0;
417  size_t dbl_id = 0;
418  size_t f_id = 0;
419  size_t prec_id = 0;
420 
421  found_nonzero = false;
422  for (long i = NAF.size() - 1; i >= 0; --i) {
423  if (!found_nonzero) {
424  /* this skips the MSB itself */
425  found_nonzero |= (NAF[i] != 0);
426  continue;
427  }
428 
429  doubling_steps1[dbl_id].reset(new mnt_miller_loop_dbl_line_eval<ppT>(
430  pb,
431  prec_P1,
432  *prec_Q1.coeffs[prec_id],
433  g_RR_at_P1s[dbl_id],
434  FMT(annotation_prefix, " doubling_steps1_%zu", dbl_id)));
435  doubling_steps2[dbl_id].reset(new mnt_miller_loop_dbl_line_eval<ppT>(
436  pb,
437  prec_P2,
438  *prec_Q2.coeffs[prec_id],
439  g_RR_at_P2s[dbl_id],
440  FMT(annotation_prefix, " doubling_steps2_%zu", dbl_id)));
441  ++prec_id;
442 
443  dbl_sqrs[dbl_id].reset(new Fqk_sqr_gadget<ppT>(
444  pb,
445  *fs[f_id],
446  *fs[f_id + 1],
447  FMT(annotation_prefix, " dbl_sqrs_%zu", dbl_id)));
448  ++f_id;
449  dbl_muls1[dbl_id].reset(new Fqk_special_mul_gadget(
450  pb,
451  *fs[f_id],
452  *g_RR_at_P1s[dbl_id],
453  *fs[f_id + 1],
454  FMT(annotation_prefix, " dbl_mul1s_%zu", dbl_id)));
455  ++f_id;
456  dbl_muls2[dbl_id].reset(new Fqk_special_mul_gadget(
457  pb,
458  (f_id + 1 == f_count ? result : *fs[f_id + 1]),
459  *g_RR_at_P2s[dbl_id],
460  *fs[f_id],
461  FMT(annotation_prefix, " dbl_mul2s_%zu", dbl_id)));
462  ++f_id;
463  ++dbl_id;
464 
465  if (NAF[i] != 0) {
466  addition_steps1[add_id].reset(
467  new mnt_miller_loop_add_line_eval<ppT>(
468  pb,
469  NAF[i] < 0,
470  prec_P1,
471  *prec_Q1.coeffs[prec_id],
472  *prec_Q1.Q,
473  g_RQ_at_P1s[add_id],
474  FMT(annotation_prefix, " addition_steps1_%zu", add_id)));
475  addition_steps2[add_id].reset(
476  new mnt_miller_loop_add_line_eval<ppT>(
477  pb,
478  NAF[i] < 0,
479  prec_P2,
480  *prec_Q2.coeffs[prec_id],
481  *prec_Q2.Q,
482  g_RQ_at_P2s[add_id],
483  FMT(annotation_prefix, " addition_steps2_%zu", add_id)));
484  ++prec_id;
485  add_muls1[add_id].reset(new Fqk_special_mul_gadget(
486  pb,
487  *fs[f_id],
488  *g_RQ_at_P1s[add_id],
489  *fs[f_id + 1],
490  FMT(annotation_prefix, " add_mul1s_%zu", add_id)));
491  ++f_id;
492  add_muls2[add_id].reset(new Fqk_special_mul_gadget(
493  pb,
494  (f_id + 1 == f_count ? result : *fs[f_id + 1]),
495  *g_RQ_at_P2s[add_id],
496  *fs[f_id],
497  FMT(annotation_prefix, " add_mul2s_%zu", add_id)));
498  ++f_id;
499  ++add_id;
500  }
501  }
502 }
503 
504 template<typename ppT>
505 void mnt_e_over_e_miller_loop_gadget<ppT>::generate_r1cs_constraints()
506 {
507  fs[0]->generate_r1cs_equals_const_constraints(FqkT::one());
508 
509  for (size_t i = 0; i < dbl_count; ++i) {
510  doubling_steps1[i]->generate_r1cs_constraints();
511  doubling_steps2[i]->generate_r1cs_constraints();
512  dbl_sqrs[i]->generate_r1cs_constraints();
513  dbl_muls1[i]->generate_r1cs_constraints();
514  dbl_muls2[i]->generate_r1cs_constraints();
515  }
516 
517  for (size_t i = 0; i < add_count; ++i) {
518  addition_steps1[i]->generate_r1cs_constraints();
519  addition_steps2[i]->generate_r1cs_constraints();
520  add_muls1[i]->generate_r1cs_constraints();
521  add_muls2[i]->generate_r1cs_constraints();
522  }
523 }
524 
525 template<typename ppT>
526 void mnt_e_over_e_miller_loop_gadget<ppT>::generate_r1cs_witness()
527 {
528  fs[0]->generate_r1cs_witness(FqkT::one());
529 
530  size_t add_id = 0;
531  size_t dbl_id = 0;
532  size_t f_id = 0;
533 
534  const auto &loop_count = mnt_pairing_params<ppT>::pairing_loop_count;
535 
536  bool found_nonzero = false;
537  std::vector<long> NAF = find_wnaf(1, loop_count);
538  for (long i = NAF.size() - 1; i >= 0; --i) {
539  if (!found_nonzero) {
540  /* this skips the MSB itself */
541  found_nonzero |= (NAF[i] != 0);
542  continue;
543  }
544 
545  doubling_steps1[dbl_id]->generate_r1cs_witness();
546  doubling_steps2[dbl_id]->generate_r1cs_witness();
547  dbl_sqrs[dbl_id]->generate_r1cs_witness();
548  ++f_id;
549  dbl_muls1[dbl_id]->generate_r1cs_witness();
550  ++f_id;
551  (f_id + 1 == f_count ? result : *fs[f_id + 1])
552  .generate_r1cs_witness(
553  fs[f_id]->get_element() *
554  g_RR_at_P2s[dbl_id]->get_element().inverse());
555  dbl_muls2[dbl_id]->generate_r1cs_witness();
556  ++f_id;
557  ++dbl_id;
558 
559  if (NAF[i] != 0) {
560  addition_steps1[add_id]->generate_r1cs_witness();
561  addition_steps2[add_id]->generate_r1cs_witness();
562  add_muls1[add_id]->generate_r1cs_witness();
563  ++f_id;
564  (f_id + 1 == f_count ? result : *fs[f_id + 1])
565  .generate_r1cs_witness(
566  fs[f_id]->get_element() *
567  g_RQ_at_P2s[add_id]->get_element().inverse());
568  add_muls2[add_id]->generate_r1cs_witness();
569  ++f_id;
570  ++add_id;
571  }
572  }
573 }
574 
575 template<typename ppT>
576 mnt_e_times_e_over_e_miller_loop_gadget<ppT>::
577  mnt_e_times_e_over_e_miller_loop_gadget(
578  protoboard<FieldT> &pb,
579  const mnt_G1_precomputation<ppT> &prec_P1,
580  const mnt_G2_precomputation<ppT> &prec_Q1,
581  const mnt_G1_precomputation<ppT> &prec_P2,
582  const mnt_G2_precomputation<ppT> &prec_Q2,
583  const mnt_G1_precomputation<ppT> &prec_P3,
584  const mnt_G2_precomputation<ppT> &prec_Q3,
585  const Fqk_variable<ppT> &result,
586  const std::string &annotation_prefix)
587  : gadget<FieldT>(pb, annotation_prefix)
588  , prec_P1(prec_P1)
589  , prec_Q1(prec_Q1)
590  , prec_P2(prec_P2)
591  , prec_Q2(prec_Q2)
592  , prec_P3(prec_P3)
593  , prec_Q3(prec_Q3)
594  , result(result)
595 {
596  const auto &loop_count = mnt_pairing_params<ppT>::pairing_loop_count;
597 
598  f_count = add_count = dbl_count = 0;
599 
600  bool found_nonzero = false;
601  std::vector<long> NAF = find_wnaf(1, loop_count);
602  for (long i = NAF.size() - 1; i >= 0; --i) {
603  if (!found_nonzero) {
604  /* this skips the MSB itself */
605  found_nonzero |= (NAF[i] != 0);
606  continue;
607  }
608 
609  ++dbl_count;
610  f_count += 4;
611 
612  if (NAF[i] != 0) {
613  ++add_count;
614  f_count += 3;
615  }
616  }
617 
618  fs.resize(f_count);
619  doubling_steps1.resize(dbl_count);
620  addition_steps1.resize(add_count);
621  doubling_steps2.resize(dbl_count);
622  addition_steps2.resize(add_count);
623  doubling_steps3.resize(dbl_count);
624  addition_steps3.resize(add_count);
625  g_RR_at_P1s.resize(dbl_count);
626  g_RQ_at_P1s.resize(add_count);
627  g_RR_at_P2s.resize(dbl_count);
628  g_RQ_at_P2s.resize(add_count);
629  g_RR_at_P3s.resize(dbl_count);
630  g_RQ_at_P3s.resize(add_count);
631 
632  for (size_t i = 0; i < f_count; ++i) {
633  fs[i].reset(
634  new Fqk_variable<ppT>(pb, FMT(annotation_prefix, " fs_%zu", i)));
635  }
636 
637  dbl_sqrs.resize(dbl_count);
638  dbl_muls1.resize(dbl_count);
639  add_muls1.resize(add_count);
640  dbl_muls2.resize(dbl_count);
641  add_muls2.resize(add_count);
642  dbl_muls3.resize(dbl_count);
643  add_muls3.resize(add_count);
644 
645  size_t add_id = 0;
646  size_t dbl_id = 0;
647  size_t f_id = 0;
648  size_t prec_id = 0;
649 
650  found_nonzero = false;
651  for (long i = NAF.size() - 1; i >= 0; --i) {
652  if (!found_nonzero) {
653  /* this skips the MSB itself */
654  found_nonzero |= (NAF[i] != 0);
655  continue;
656  }
657 
658  doubling_steps1[dbl_id].reset(new mnt_miller_loop_dbl_line_eval<ppT>(
659  pb,
660  prec_P1,
661  *prec_Q1.coeffs[prec_id],
662  g_RR_at_P1s[dbl_id],
663  FMT(annotation_prefix, " doubling_steps1_%zu", dbl_id)));
664  doubling_steps2[dbl_id].reset(new mnt_miller_loop_dbl_line_eval<ppT>(
665  pb,
666  prec_P2,
667  *prec_Q2.coeffs[prec_id],
668  g_RR_at_P2s[dbl_id],
669  FMT(annotation_prefix, " doubling_steps2_%zu", dbl_id)));
670  doubling_steps3[dbl_id].reset(new mnt_miller_loop_dbl_line_eval<ppT>(
671  pb,
672  prec_P3,
673  *prec_Q3.coeffs[prec_id],
674  g_RR_at_P3s[dbl_id],
675  FMT(annotation_prefix, " doubling_steps3_%zu", dbl_id)));
676  ++prec_id;
677 
678  dbl_sqrs[dbl_id].reset(new Fqk_sqr_gadget<ppT>(
679  pb,
680  *fs[f_id],
681  *fs[f_id + 1],
682  FMT(annotation_prefix, " dbl_sqrs_%zu", dbl_id)));
683  ++f_id;
684  dbl_muls1[dbl_id].reset(new Fqk_special_mul_gadget(
685  pb,
686  *fs[f_id],
687  *g_RR_at_P1s[dbl_id],
688  *fs[f_id + 1],
689  FMT(annotation_prefix, " dbl_muls1_%zu", dbl_id)));
690  ++f_id;
691  dbl_muls2[dbl_id].reset(new Fqk_special_mul_gadget(
692  pb,
693  *fs[f_id],
694  *g_RR_at_P2s[dbl_id],
695  *fs[f_id + 1],
696  FMT(annotation_prefix, " dbl_muls2_%zu", dbl_id)));
697  ++f_id;
698  dbl_muls3[dbl_id].reset(new Fqk_special_mul_gadget(
699  pb,
700  (f_id + 1 == f_count ? result : *fs[f_id + 1]),
701  *g_RR_at_P3s[dbl_id],
702  *fs[f_id],
703  FMT(annotation_prefix, " dbl_muls3_%zu", dbl_id)));
704  ++f_id;
705  ++dbl_id;
706 
707  if (NAF[i] != 0) {
708  addition_steps1[add_id].reset(
709  new mnt_miller_loop_add_line_eval<ppT>(
710  pb,
711  NAF[i] < 0,
712  prec_P1,
713  *prec_Q1.coeffs[prec_id],
714  *prec_Q1.Q,
715  g_RQ_at_P1s[add_id],
716  FMT(annotation_prefix, " addition_steps1_%zu", add_id)));
717  addition_steps2[add_id].reset(
718  new mnt_miller_loop_add_line_eval<ppT>(
719  pb,
720  NAF[i] < 0,
721  prec_P2,
722  *prec_Q2.coeffs[prec_id],
723  *prec_Q2.Q,
724  g_RQ_at_P2s[add_id],
725  FMT(annotation_prefix, " addition_steps2_%zu", add_id)));
726  addition_steps3[add_id].reset(
727  new mnt_miller_loop_add_line_eval<ppT>(
728  pb,
729  NAF[i] < 0,
730  prec_P3,
731  *prec_Q3.coeffs[prec_id],
732  *prec_Q3.Q,
733  g_RQ_at_P3s[add_id],
734  FMT(annotation_prefix, " addition_steps3_%zu", add_id)));
735  ++prec_id;
736  add_muls1[add_id].reset(new Fqk_special_mul_gadget(
737  pb,
738  *fs[f_id],
739  *g_RQ_at_P1s[add_id],
740  *fs[f_id + 1],
741  FMT(annotation_prefix, " add_muls1_%zu", add_id)));
742  ++f_id;
743  add_muls2[add_id].reset(new Fqk_special_mul_gadget(
744  pb,
745  *fs[f_id],
746  *g_RQ_at_P2s[add_id],
747  *fs[f_id + 1],
748  FMT(annotation_prefix, " add_muls2_%zu", add_id)));
749  ++f_id;
750  add_muls3[add_id].reset(new Fqk_special_mul_gadget(
751  pb,
752  (f_id + 1 == f_count ? result : *fs[f_id + 1]),
753  *g_RQ_at_P3s[add_id],
754  *fs[f_id],
755  FMT(annotation_prefix, " add_muls3_%zu", add_id)));
756  ++f_id;
757  ++add_id;
758  }
759  }
760 }
761 
762 template<typename ppT>
763 void mnt_e_times_e_over_e_miller_loop_gadget<ppT>::generate_r1cs_constraints()
764 {
765  fs[0]->generate_r1cs_equals_const_constraints(FqkT::one());
766 
767  for (size_t i = 0; i < dbl_count; ++i) {
768  doubling_steps1[i]->generate_r1cs_constraints();
769  doubling_steps2[i]->generate_r1cs_constraints();
770  doubling_steps3[i]->generate_r1cs_constraints();
771  dbl_sqrs[i]->generate_r1cs_constraints();
772  dbl_muls1[i]->generate_r1cs_constraints();
773  dbl_muls2[i]->generate_r1cs_constraints();
774  dbl_muls3[i]->generate_r1cs_constraints();
775  }
776 
777  for (size_t i = 0; i < add_count; ++i) {
778  addition_steps1[i]->generate_r1cs_constraints();
779  addition_steps2[i]->generate_r1cs_constraints();
780  addition_steps3[i]->generate_r1cs_constraints();
781  add_muls1[i]->generate_r1cs_constraints();
782  add_muls2[i]->generate_r1cs_constraints();
783  add_muls3[i]->generate_r1cs_constraints();
784  }
785 }
786 
787 template<typename ppT>
788 void mnt_e_times_e_over_e_miller_loop_gadget<ppT>::generate_r1cs_witness()
789 {
790  fs[0]->generate_r1cs_witness(FqkT::one());
791 
792  size_t add_id = 0;
793  size_t dbl_id = 0;
794  size_t f_id = 0;
795 
796  const auto &loop_count = mnt_pairing_params<ppT>::pairing_loop_count;
797 
798  bool found_nonzero = false;
799  std::vector<long> NAF = find_wnaf(1, loop_count);
800  for (long i = NAF.size() - 1; i >= 0; --i) {
801  if (!found_nonzero) {
802  /* this skips the MSB itself */
803  found_nonzero |= (NAF[i] != 0);
804  continue;
805  }
806 
807  doubling_steps1[dbl_id]->generate_r1cs_witness();
808  doubling_steps2[dbl_id]->generate_r1cs_witness();
809  doubling_steps3[dbl_id]->generate_r1cs_witness();
810  dbl_sqrs[dbl_id]->generate_r1cs_witness();
811  ++f_id;
812  dbl_muls1[dbl_id]->generate_r1cs_witness();
813  ++f_id;
814  dbl_muls2[dbl_id]->generate_r1cs_witness();
815  ++f_id;
816  (f_id + 1 == f_count ? result : *fs[f_id + 1])
817  .generate_r1cs_witness(
818  fs[f_id]->get_element() *
819  g_RR_at_P3s[dbl_id]->get_element().inverse());
820  dbl_muls3[dbl_id]->generate_r1cs_witness();
821  ++f_id;
822  ++dbl_id;
823 
824  if (NAF[i] != 0) {
825  addition_steps1[add_id]->generate_r1cs_witness();
826  addition_steps2[add_id]->generate_r1cs_witness();
827  addition_steps3[add_id]->generate_r1cs_witness();
828  add_muls1[add_id]->generate_r1cs_witness();
829  ++f_id;
830  add_muls2[add_id]->generate_r1cs_witness();
831  ++f_id;
832  (f_id + 1 == f_count ? result : *fs[f_id + 1])
833  .generate_r1cs_witness(
834  fs[f_id]->get_element() *
835  g_RQ_at_P3s[add_id]->get_element().inverse());
836  add_muls3[add_id]->generate_r1cs_witness();
837  ++f_id;
838  ++add_id;
839  }
840  }
841 }
842 
843 template<typename ppT>
844 mnt_e_times_e_times_e_over_e_miller_loop_gadget<ppT>::
845  mnt_e_times_e_times_e_over_e_miller_loop_gadget(
846  protoboard<FieldT> &pb,
847  const G1_precomputation<ppT> &prec_P1,
848  const G2_precomputation<ppT> &prec_Q1,
849  const G1_precomputation<ppT> &prec_P2,
850  const G2_precomputation<ppT> &prec_Q2,
851  const G1_precomputation<ppT> &prec_P3,
852  const G2_precomputation<ppT> &prec_Q3,
853  const G1_precomputation<ppT> &prec_P4,
854  const G2_precomputation<ppT> &prec_Q4,
855  const Fqk_variable<ppT> &result,
856  const std::string &annotation_prefix)
857  : gadget<FieldT>(pb, annotation_prefix)
858  , prec_P1(prec_P1)
859  , prec_Q1(prec_Q1)
860  , prec_P2(prec_P2)
861  , prec_Q2(prec_Q2)
862  , prec_P3(prec_P3)
863  , prec_Q3(prec_Q3)
864  , prec_P4(prec_P4)
865  , prec_Q4(prec_Q4)
866  , result(result)
867 {
868  const auto &loop_count = mnt_pairing_params<ppT>::pairing_loop_count;
869 
870  f_count = add_count = dbl_count = 0;
871 
872  bool found_nonzero = false;
873  std::vector<long> NAF = find_wnaf(1, loop_count);
874  for (long i = NAF.size() - 1; i >= 0; --i) {
875  if (!found_nonzero) {
876  /* this skips the MSB itself */
877  found_nonzero |= (NAF[i] != 0);
878  continue;
879  }
880 
881  ++dbl_count;
882  f_count += 5;
883 
884  if (NAF[i] != 0) {
885  ++add_count;
886  f_count += 4;
887  }
888  }
889 
890  fs.resize(f_count);
891  doubling_steps1.resize(dbl_count);
892  addition_steps1.resize(add_count);
893  doubling_steps2.resize(dbl_count);
894  addition_steps2.resize(add_count);
895  doubling_steps3.resize(dbl_count);
896  addition_steps3.resize(add_count);
897  doubling_steps4.resize(dbl_count);
898  addition_steps4.resize(add_count);
899  g_RR_at_P1s.resize(dbl_count);
900  g_RQ_at_P1s.resize(add_count);
901  g_RR_at_P2s.resize(dbl_count);
902  g_RQ_at_P2s.resize(add_count);
903  g_RR_at_P3s.resize(dbl_count);
904  g_RQ_at_P3s.resize(add_count);
905  g_RR_at_P4s.resize(dbl_count);
906  g_RQ_at_P4s.resize(add_count);
907 
908  for (size_t i = 0; i < f_count; ++i) {
909  fs[i].reset(
910  new Fqk_variable<ppT>(pb, FMT(annotation_prefix, " fs_%zu", i)));
911  }
912 
913  dbl_sqrs.resize(dbl_count);
914  dbl_muls1.resize(dbl_count);
915  add_muls1.resize(add_count);
916  dbl_muls2.resize(dbl_count);
917  add_muls2.resize(add_count);
918  dbl_muls3.resize(dbl_count);
919  add_muls3.resize(add_count);
920  dbl_muls4.resize(dbl_count);
921  add_muls4.resize(add_count);
922 
923  size_t add_id = 0;
924  size_t dbl_id = 0;
925  size_t f_id = 0;
926  size_t prec_id = 0;
927 
928  found_nonzero = false;
929  for (long i = NAF.size() - 1; i >= 0; --i) {
930  if (!found_nonzero) {
931  /* this skips the MSB itself */
932  found_nonzero |= (NAF[i] != 0);
933  continue;
934  }
935 
936  doubling_steps1[dbl_id].reset(new mnt_miller_loop_dbl_line_eval<ppT>(
937  pb,
938  prec_P1,
939  *prec_Q1.coeffs[prec_id],
940  g_RR_at_P1s[dbl_id],
941  FMT(annotation_prefix, " doubling_steps1_%zu", dbl_id)));
942  doubling_steps2[dbl_id].reset(new mnt_miller_loop_dbl_line_eval<ppT>(
943  pb,
944  prec_P2,
945  *prec_Q2.coeffs[prec_id],
946  g_RR_at_P2s[dbl_id],
947  FMT(annotation_prefix, " doubling_steps2_%zu", dbl_id)));
948  doubling_steps3[dbl_id].reset(new mnt_miller_loop_dbl_line_eval<ppT>(
949  pb,
950  prec_P3,
951  *prec_Q3.coeffs[prec_id],
952  g_RR_at_P3s[dbl_id],
953  FMT(annotation_prefix, " doubling_steps3_%zu", dbl_id)));
954  doubling_steps4[dbl_id].reset(new mnt_miller_loop_dbl_line_eval<ppT>(
955  pb,
956  prec_P4,
957  *prec_Q4.coeffs[prec_id],
958  g_RR_at_P4s[dbl_id],
959  FMT(annotation_prefix, " doubling_steps4_%zu", dbl_id)));
960  ++prec_id;
961 
962  dbl_sqrs[dbl_id].reset(new Fqk_sqr_gadget<ppT>(
963  pb,
964  *fs[f_id],
965  *fs[f_id + 1],
966  FMT(annotation_prefix, " dbl_sqrs_%zu", dbl_id)));
967  ++f_id;
968  dbl_muls1[dbl_id].reset(new Fqk_special_mul_gadget(
969  pb,
970  *fs[f_id],
971  *g_RR_at_P1s[dbl_id],
972  *fs[f_id + 1],
973  FMT(annotation_prefix, " dbl_muls1_%zu", dbl_id)));
974  ++f_id;
975  dbl_muls2[dbl_id].reset(new Fqk_special_mul_gadget(
976  pb,
977  *fs[f_id],
978  *g_RR_at_P2s[dbl_id],
979  *fs[f_id + 1],
980  FMT(annotation_prefix, " dbl_muls2_%zu", dbl_id)));
981  ++f_id;
982  dbl_muls3[dbl_id].reset(new Fqk_special_mul_gadget(
983  pb,
984  *fs[f_id],
985  *g_RR_at_P3s[dbl_id],
986  *fs[f_id + 1],
987  FMT(annotation_prefix, " dbl_muls3_%zu", dbl_id)));
988  ++f_id;
989  dbl_muls4[dbl_id].reset(new Fqk_special_mul_gadget(
990  pb,
991  (f_id + 1 == f_count ? result : *fs[f_id + 1]),
992  *g_RR_at_P4s[dbl_id],
993  *fs[f_id],
994  FMT(annotation_prefix, " dbl_muls4_%zu", dbl_id)));
995  ++f_id;
996  ++dbl_id;
997 
998  if (NAF[i] != 0) {
999  addition_steps1[add_id].reset(
1000  new mnt_miller_loop_add_line_eval<ppT>(
1001  pb,
1002  NAF[i] < 0,
1003  prec_P1,
1004  *prec_Q1.coeffs[prec_id],
1005  *prec_Q1.Q,
1006  g_RQ_at_P1s[add_id],
1007  FMT(annotation_prefix, " addition_steps1_%zu", add_id)));
1008  addition_steps2[add_id].reset(
1009  new mnt_miller_loop_add_line_eval<ppT>(
1010  pb,
1011  NAF[i] < 0,
1012  prec_P2,
1013  *prec_Q2.coeffs[prec_id],
1014  *prec_Q2.Q,
1015  g_RQ_at_P2s[add_id],
1016  FMT(annotation_prefix, " addition_steps2_%zu", add_id)));
1017  addition_steps3[add_id].reset(
1018  new mnt_miller_loop_add_line_eval<ppT>(
1019  pb,
1020  NAF[i] < 0,
1021  prec_P3,
1022  *prec_Q3.coeffs[prec_id],
1023  *prec_Q3.Q,
1024  g_RQ_at_P3s[add_id],
1025  FMT(annotation_prefix, " addition_steps3_%zu", add_id)));
1026  addition_steps4[add_id].reset(
1027  new mnt_miller_loop_add_line_eval<ppT>(
1028  pb,
1029  NAF[i] < 0,
1030  prec_P4,
1031  *prec_Q4.coeffs[prec_id],
1032  *prec_Q4.Q,
1033  g_RQ_at_P4s[add_id],
1034  FMT(annotation_prefix, " addition_steps4_%zu", add_id)));
1035  ++prec_id;
1036  add_muls1[add_id].reset(new Fqk_special_mul_gadget(
1037  pb,
1038  *fs[f_id],
1039  *g_RQ_at_P1s[add_id],
1040  *fs[f_id + 1],
1041  FMT(annotation_prefix, " add_muls1_%zu", add_id)));
1042  ++f_id;
1043  add_muls2[add_id].reset(new Fqk_special_mul_gadget(
1044  pb,
1045  *fs[f_id],
1046  *g_RQ_at_P2s[add_id],
1047  *fs[f_id + 1],
1048  FMT(annotation_prefix, " add_muls2_%zu", add_id)));
1049  ++f_id;
1050  add_muls3[add_id].reset(new Fqk_special_mul_gadget(
1051  pb,
1052  *fs[f_id],
1053  *g_RQ_at_P3s[add_id],
1054  *fs[f_id + 1],
1055  FMT(annotation_prefix, " add_muls3_%zu", add_id)));
1056  ++f_id;
1057  add_muls4[add_id].reset(new Fqk_special_mul_gadget(
1058  pb,
1059  (f_id + 1 == f_count ? result : *fs[f_id + 1]),
1060  *g_RQ_at_P4s[add_id],
1061  *fs[f_id],
1062  FMT(annotation_prefix, " add_muls4_%zu", add_id)));
1063  ++f_id;
1064  ++add_id;
1065  }
1066  }
1067 }
1068 
1069 template<typename ppT>
1070 void mnt_e_times_e_times_e_over_e_miller_loop_gadget<
1071  ppT>::generate_r1cs_constraints()
1072 {
1073  fs[0]->generate_r1cs_equals_const_constraints(FqkT::one());
1074 
1075  for (size_t i = 0; i < dbl_count; ++i) {
1076  doubling_steps1[i]->generate_r1cs_constraints();
1077  doubling_steps2[i]->generate_r1cs_constraints();
1078  doubling_steps3[i]->generate_r1cs_constraints();
1079  doubling_steps4[i]->generate_r1cs_constraints();
1080  dbl_sqrs[i]->generate_r1cs_constraints();
1081  dbl_muls1[i]->generate_r1cs_constraints();
1082  dbl_muls2[i]->generate_r1cs_constraints();
1083  dbl_muls3[i]->generate_r1cs_constraints();
1084  dbl_muls4[i]->generate_r1cs_constraints();
1085  }
1086 
1087  for (size_t i = 0; i < add_count; ++i) {
1088  addition_steps1[i]->generate_r1cs_constraints();
1089  addition_steps2[i]->generate_r1cs_constraints();
1090  addition_steps3[i]->generate_r1cs_constraints();
1091  addition_steps4[i]->generate_r1cs_constraints();
1092  add_muls1[i]->generate_r1cs_constraints();
1093  add_muls2[i]->generate_r1cs_constraints();
1094  add_muls3[i]->generate_r1cs_constraints();
1095  add_muls4[i]->generate_r1cs_constraints();
1096  }
1097 }
1098 
1099 template<typename ppT>
1100 void mnt_e_times_e_times_e_over_e_miller_loop_gadget<
1101  ppT>::generate_r1cs_witness()
1102 {
1103  fs[0]->generate_r1cs_witness(FqkT::one());
1104 
1105  size_t add_id = 0;
1106  size_t dbl_id = 0;
1107  size_t f_id = 0;
1108 
1109  const auto &loop_count = mnt_pairing_params<ppT>::pairing_loop_count;
1110 
1111  bool found_nonzero = false;
1112  std::vector<long> NAF = find_wnaf(1, loop_count);
1113  for (long i = NAF.size() - 1; i >= 0; --i) {
1114  if (!found_nonzero) {
1115  /* this skips the MSB itself */
1116  found_nonzero |= (NAF[i] != 0);
1117  continue;
1118  }
1119 
1120  doubling_steps1[dbl_id]->generate_r1cs_witness();
1121  doubling_steps2[dbl_id]->generate_r1cs_witness();
1122  doubling_steps3[dbl_id]->generate_r1cs_witness();
1123  doubling_steps4[dbl_id]->generate_r1cs_witness();
1124  dbl_sqrs[dbl_id]->generate_r1cs_witness();
1125  ++f_id;
1126  dbl_muls1[dbl_id]->generate_r1cs_witness();
1127  ++f_id;
1128  dbl_muls2[dbl_id]->generate_r1cs_witness();
1129  ++f_id;
1130  dbl_muls3[dbl_id]->generate_r1cs_witness();
1131  ++f_id;
1132  (f_id + 1 == f_count ? result : *fs[f_id + 1])
1133  .generate_r1cs_witness(
1134  fs[f_id]->get_element() *
1135  g_RR_at_P4s[dbl_id]->get_element().inverse());
1136  dbl_muls4[dbl_id]->generate_r1cs_witness();
1137  ++f_id;
1138  ++dbl_id;
1139 
1140  if (NAF[i] != 0) {
1141  addition_steps1[add_id]->generate_r1cs_witness();
1142  addition_steps2[add_id]->generate_r1cs_witness();
1143  addition_steps3[add_id]->generate_r1cs_witness();
1144  addition_steps4[add_id]->generate_r1cs_witness();
1145  add_muls1[add_id]->generate_r1cs_witness();
1146  ++f_id;
1147  add_muls2[add_id]->generate_r1cs_witness();
1148  ++f_id;
1149  add_muls3[add_id]->generate_r1cs_witness();
1150  ++f_id;
1151  (f_id + 1 == f_count ? result : *fs[f_id + 1])
1152  .generate_r1cs_witness(
1153  fs[f_id]->get_element() *
1154  g_RQ_at_P4s[add_id]->get_element().inverse());
1155  add_muls4[add_id]->generate_r1cs_witness();
1156  ++f_id;
1157  ++add_id;
1158  }
1159  }
1160 }
1161 
1162 } // namespace libsnark
1163 
1164 #endif // LIBSNARK_GADGETLIB1_GADGETS_PAIRING_MNT_MNT_MILLER_LOOP_TCC_