2  *****************************************************************************
 
    4  Implementation of interfaces for gadgets for Miller loops.
 
    6  See weierstrass_miller_loop.hpp .
 
    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  *****************************************************************************/
 
   14 #ifndef LIBSNARK_GADGETLIB1_GADGETS_PAIRING_MNT_MNT_MILLER_LOOP_TCC_
 
   15 #define LIBSNARK_GADGETLIB1_GADGETS_PAIRING_MNT_MNT_MILLER_LOOP_TCC_
 
   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"
 
   21 #include <libff/algebra/scalar_multiplication/wnaf.hpp>
 
   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);
 
   32   (later in Miller loop: f = f.squared() * g_RR_at_P)
 
   35 /* Note the slight interface change: this gadget will allocate g_RR_at_P inside
 
   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)
 
   47     , g_RR_at_P(g_RR_at_P)
 
   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>(
 
   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())));
 
   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>(
 
   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")));
 
   78     g_RR_at_P.reset(new Fqk_variable<ppT>(
 
   80         *(prec_P.PY_twist_squared),
 
   82         FMT(annotation_prefix, " g_RR_at_P")));
 
   85 template<typename ppT>
 
   86 void mnt_miller_loop_dbl_line_eval<ppT>::generate_r1cs_constraints()
 
   88     if (!gamma_twist->is_constant() && !prec_P.P->X.is_constant()) {
 
   89         compute_g_RR_at_P_c1->generate_r1cs_constraints();
 
   93 template<typename ppT>
 
   94 void mnt_miller_loop_dbl_line_eval<ppT>::generate_r1cs_witness()
 
   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);
 
  105     if (!gamma_twist->is_constant() && !prec_P.P->X.is_constant()) {
 
  106         compute_g_RR_at_P_c1->generate_r1cs_witness();
 
  108     g_RR_at_P->evaluate();
 
  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);
 
  116   (later in Miller loop: f = f * g_RQ_at_P)
 
  118   If invert_Q is set to true: use -QY in place of QY everywhere above.
 
  121 /* Note the slight interface change: this gadget will allocate g_RQ_at_P inside
 
  123 template<typename ppT>
 
  124 mnt_miller_loop_add_line_eval<ppT>::mnt_miller_loop_add_line_eval(
 
  125     protoboard<FieldT> &pb,
 
  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)
 
  137     , g_RQ_at_P(g_RQ_at_P)
 
  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>(
 
  149                 FMT(annotation_prefix, " tmp")) +
 
  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())));
 
  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>(
 
  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")));
 
  170     g_RQ_at_P.reset(new Fqk_variable<ppT>(
 
  172         *(prec_P.PY_twist_squared),
 
  174         FMT(annotation_prefix, " g_RQ_at_P")));
 
  177 template<typename ppT>
 
  178 void mnt_miller_loop_add_line_eval<ppT>::generate_r1cs_constraints()
 
  180     if (!gamma_twist->is_constant() && !prec_P.P->X.is_constant()) {
 
  181         compute_g_RQ_at_P_c1->generate_r1cs_constraints();
 
  185 template<typename ppT>
 
  186 void mnt_miller_loop_add_line_eval<ppT>::generate_r1cs_witness()
 
  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);
 
  197     if (!gamma_twist->is_constant() && !prec_P.P->X.is_constant()) {
 
  198         compute_g_RQ_at_P_c1->generate_r1cs_witness();
 
  200     g_RQ_at_P->evaluate();
 
  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)
 
  215     const auto &loop_count = mnt_pairing_params<ppT>::pairing_loop_count;
 
  217     f_count = add_count = dbl_count = 0;
 
  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);
 
  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);
 
  243     for (size_t i = 0; i < f_count; ++i) {
 
  245             new Fqk_variable<ppT>(pb, FMT(annotation_prefix, " fs_%zu", i)));
 
  248     dbl_sqrs.resize(dbl_count);
 
  249     dbl_muls.resize(dbl_count);
 
  250     add_muls.resize(add_count);
 
  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);
 
  265         doubling_steps[dbl_id].reset(new mnt_miller_loop_dbl_line_eval<ppT>(
 
  268             *prec_Q.coeffs[prec_id],
 
  270             FMT(annotation_prefix, " doubling_steps_%zu", dbl_id)));
 
  272         dbl_sqrs[dbl_id].reset(new Fqk_sqr_gadget<ppT>(
 
  276             FMT(annotation_prefix, " dbl_sqrs_%zu", dbl_id)));
 
  278         dbl_muls[dbl_id].reset(new Fqk_special_mul_gadget(
 
  282             (f_id + 1 == f_count ? result : *fs[f_id + 1]),
 
  283             FMT(annotation_prefix, " dbl_muls_%zu", dbl_id)));
 
  288             addition_steps[add_id].reset(new mnt_miller_loop_add_line_eval<ppT>(
 
  292                 *prec_Q.coeffs[prec_id],
 
  295                 FMT(annotation_prefix, " addition_steps_%zu", add_id)));
 
  297             add_muls[add_id].reset(new Fqk_special_mul_gadget(
 
  301                 (f_id + 1 == f_count ? result : *fs[f_id + 1]),
 
  302                 FMT(annotation_prefix, " add_muls_%zu", add_id)));
 
  309 template<typename ppT>
 
  310 void mnt_miller_loop_gadget<ppT>::generate_r1cs_constraints()
 
  312     fs[0]->generate_r1cs_equals_const_constraints(FqkT::one());
 
  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();
 
  320     for (size_t i = 0; i < add_count; ++i) {
 
  321         addition_steps[i]->generate_r1cs_constraints();
 
  322         add_muls[i]->generate_r1cs_constraints();
 
  326 template<typename ppT> void mnt_miller_loop_gadget<ppT>::generate_r1cs_witness()
 
  328     fs[0]->generate_r1cs_witness(FqkT::one());
 
  333     const auto &loop_count = mnt_pairing_params<ppT>::pairing_loop_count;
 
  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);
 
  344         doubling_steps[dbl_id]->generate_r1cs_witness();
 
  345         dbl_sqrs[dbl_id]->generate_r1cs_witness();
 
  346         dbl_muls[dbl_id]->generate_r1cs_witness();
 
  350             addition_steps[add_id]->generate_r1cs_witness();
 
  351             add_muls[add_id]->generate_r1cs_witness();
 
  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)
 
  373     const auto &loop_count = mnt_pairing_params<ppT>::pairing_loop_count;
 
  375     f_count = add_count = dbl_count = 0;
 
  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);
 
  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);
 
  405     for (size_t i = 0; i < f_count; ++i) {
 
  407             new Fqk_variable<ppT>(pb, FMT(annotation_prefix, " fs_%zu", i)));
 
  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);
 
  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);
 
  429         doubling_steps1[dbl_id].reset(new mnt_miller_loop_dbl_line_eval<ppT>(
 
  432             *prec_Q1.coeffs[prec_id],
 
  434             FMT(annotation_prefix, " doubling_steps1_%zu", dbl_id)));
 
  435         doubling_steps2[dbl_id].reset(new mnt_miller_loop_dbl_line_eval<ppT>(
 
  438             *prec_Q2.coeffs[prec_id],
 
  440             FMT(annotation_prefix, " doubling_steps2_%zu", dbl_id)));
 
  443         dbl_sqrs[dbl_id].reset(new Fqk_sqr_gadget<ppT>(
 
  447             FMT(annotation_prefix, " dbl_sqrs_%zu", dbl_id)));
 
  449         dbl_muls1[dbl_id].reset(new Fqk_special_mul_gadget(
 
  452             *g_RR_at_P1s[dbl_id],
 
  454             FMT(annotation_prefix, " dbl_mul1s_%zu", dbl_id)));
 
  456         dbl_muls2[dbl_id].reset(new Fqk_special_mul_gadget(
 
  458             (f_id + 1 == f_count ? result : *fs[f_id + 1]),
 
  459             *g_RR_at_P2s[dbl_id],
 
  461             FMT(annotation_prefix, " dbl_mul2s_%zu", dbl_id)));
 
  466             addition_steps1[add_id].reset(
 
  467                 new mnt_miller_loop_add_line_eval<ppT>(
 
  471                     *prec_Q1.coeffs[prec_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>(
 
  480                     *prec_Q2.coeffs[prec_id],
 
  483                     FMT(annotation_prefix, " addition_steps2_%zu", add_id)));
 
  485             add_muls1[add_id].reset(new Fqk_special_mul_gadget(
 
  488                 *g_RQ_at_P1s[add_id],
 
  490                 FMT(annotation_prefix, " add_mul1s_%zu", add_id)));
 
  492             add_muls2[add_id].reset(new Fqk_special_mul_gadget(
 
  494                 (f_id + 1 == f_count ? result : *fs[f_id + 1]),
 
  495                 *g_RQ_at_P2s[add_id],
 
  497                 FMT(annotation_prefix, " add_mul2s_%zu", add_id)));
 
  504 template<typename ppT>
 
  505 void mnt_e_over_e_miller_loop_gadget<ppT>::generate_r1cs_constraints()
 
  507     fs[0]->generate_r1cs_equals_const_constraints(FqkT::one());
 
  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();
 
  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();
 
  525 template<typename ppT>
 
  526 void mnt_e_over_e_miller_loop_gadget<ppT>::generate_r1cs_witness()
 
  528     fs[0]->generate_r1cs_witness(FqkT::one());
 
  534     const auto &loop_count = mnt_pairing_params<ppT>::pairing_loop_count;
 
  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);
 
  545         doubling_steps1[dbl_id]->generate_r1cs_witness();
 
  546         doubling_steps2[dbl_id]->generate_r1cs_witness();
 
  547         dbl_sqrs[dbl_id]->generate_r1cs_witness();
 
  549         dbl_muls1[dbl_id]->generate_r1cs_witness();
 
  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();
 
  560             addition_steps1[add_id]->generate_r1cs_witness();
 
  561             addition_steps2[add_id]->generate_r1cs_witness();
 
  562             add_muls1[add_id]->generate_r1cs_witness();
 
  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();
 
  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)
 
  596     const auto &loop_count = mnt_pairing_params<ppT>::pairing_loop_count;
 
  598     f_count = add_count = dbl_count = 0;
 
  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);
 
  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);
 
  632     for (size_t i = 0; i < f_count; ++i) {
 
  634             new Fqk_variable<ppT>(pb, FMT(annotation_prefix, " fs_%zu", i)));
 
  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);
 
  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);
 
  658         doubling_steps1[dbl_id].reset(new mnt_miller_loop_dbl_line_eval<ppT>(
 
  661             *prec_Q1.coeffs[prec_id],
 
  663             FMT(annotation_prefix, " doubling_steps1_%zu", dbl_id)));
 
  664         doubling_steps2[dbl_id].reset(new mnt_miller_loop_dbl_line_eval<ppT>(
 
  667             *prec_Q2.coeffs[prec_id],
 
  669             FMT(annotation_prefix, " doubling_steps2_%zu", dbl_id)));
 
  670         doubling_steps3[dbl_id].reset(new mnt_miller_loop_dbl_line_eval<ppT>(
 
  673             *prec_Q3.coeffs[prec_id],
 
  675             FMT(annotation_prefix, " doubling_steps3_%zu", dbl_id)));
 
  678         dbl_sqrs[dbl_id].reset(new Fqk_sqr_gadget<ppT>(
 
  682             FMT(annotation_prefix, " dbl_sqrs_%zu", dbl_id)));
 
  684         dbl_muls1[dbl_id].reset(new Fqk_special_mul_gadget(
 
  687             *g_RR_at_P1s[dbl_id],
 
  689             FMT(annotation_prefix, " dbl_muls1_%zu", dbl_id)));
 
  691         dbl_muls2[dbl_id].reset(new Fqk_special_mul_gadget(
 
  694             *g_RR_at_P2s[dbl_id],
 
  696             FMT(annotation_prefix, " dbl_muls2_%zu", dbl_id)));
 
  698         dbl_muls3[dbl_id].reset(new Fqk_special_mul_gadget(
 
  700             (f_id + 1 == f_count ? result : *fs[f_id + 1]),
 
  701             *g_RR_at_P3s[dbl_id],
 
  703             FMT(annotation_prefix, " dbl_muls3_%zu", dbl_id)));
 
  708             addition_steps1[add_id].reset(
 
  709                 new mnt_miller_loop_add_line_eval<ppT>(
 
  713                     *prec_Q1.coeffs[prec_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>(
 
  722                     *prec_Q2.coeffs[prec_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>(
 
  731                     *prec_Q3.coeffs[prec_id],
 
  734                     FMT(annotation_prefix, " addition_steps3_%zu", add_id)));
 
  736             add_muls1[add_id].reset(new Fqk_special_mul_gadget(
 
  739                 *g_RQ_at_P1s[add_id],
 
  741                 FMT(annotation_prefix, " add_muls1_%zu", add_id)));
 
  743             add_muls2[add_id].reset(new Fqk_special_mul_gadget(
 
  746                 *g_RQ_at_P2s[add_id],
 
  748                 FMT(annotation_prefix, " add_muls2_%zu", add_id)));
 
  750             add_muls3[add_id].reset(new Fqk_special_mul_gadget(
 
  752                 (f_id + 1 == f_count ? result : *fs[f_id + 1]),
 
  753                 *g_RQ_at_P3s[add_id],
 
  755                 FMT(annotation_prefix, " add_muls3_%zu", add_id)));
 
  762 template<typename ppT>
 
  763 void mnt_e_times_e_over_e_miller_loop_gadget<ppT>::generate_r1cs_constraints()
 
  765     fs[0]->generate_r1cs_equals_const_constraints(FqkT::one());
 
  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();
 
  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();
 
  787 template<typename ppT>
 
  788 void mnt_e_times_e_over_e_miller_loop_gadget<ppT>::generate_r1cs_witness()
 
  790     fs[0]->generate_r1cs_witness(FqkT::one());
 
  796     const auto &loop_count = mnt_pairing_params<ppT>::pairing_loop_count;
 
  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);
 
  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();
 
  812         dbl_muls1[dbl_id]->generate_r1cs_witness();
 
  814         dbl_muls2[dbl_id]->generate_r1cs_witness();
 
  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();
 
  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();
 
  830             add_muls2[add_id]->generate_r1cs_witness();
 
  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();
 
  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)
 
  868     const auto &loop_count = mnt_pairing_params<ppT>::pairing_loop_count;
 
  870     f_count = add_count = dbl_count = 0;
 
  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);
 
  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);
 
  908     for (size_t i = 0; i < f_count; ++i) {
 
  910             new Fqk_variable<ppT>(pb, FMT(annotation_prefix, " fs_%zu", i)));
 
  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);
 
  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);
 
  936         doubling_steps1[dbl_id].reset(new mnt_miller_loop_dbl_line_eval<ppT>(
 
  939             *prec_Q1.coeffs[prec_id],
 
  941             FMT(annotation_prefix, " doubling_steps1_%zu", dbl_id)));
 
  942         doubling_steps2[dbl_id].reset(new mnt_miller_loop_dbl_line_eval<ppT>(
 
  945             *prec_Q2.coeffs[prec_id],
 
  947             FMT(annotation_prefix, " doubling_steps2_%zu", dbl_id)));
 
  948         doubling_steps3[dbl_id].reset(new mnt_miller_loop_dbl_line_eval<ppT>(
 
  951             *prec_Q3.coeffs[prec_id],
 
  953             FMT(annotation_prefix, " doubling_steps3_%zu", dbl_id)));
 
  954         doubling_steps4[dbl_id].reset(new mnt_miller_loop_dbl_line_eval<ppT>(
 
  957             *prec_Q4.coeffs[prec_id],
 
  959             FMT(annotation_prefix, " doubling_steps4_%zu", dbl_id)));
 
  962         dbl_sqrs[dbl_id].reset(new Fqk_sqr_gadget<ppT>(
 
  966             FMT(annotation_prefix, " dbl_sqrs_%zu", dbl_id)));
 
  968         dbl_muls1[dbl_id].reset(new Fqk_special_mul_gadget(
 
  971             *g_RR_at_P1s[dbl_id],
 
  973             FMT(annotation_prefix, " dbl_muls1_%zu", dbl_id)));
 
  975         dbl_muls2[dbl_id].reset(new Fqk_special_mul_gadget(
 
  978             *g_RR_at_P2s[dbl_id],
 
  980             FMT(annotation_prefix, " dbl_muls2_%zu", dbl_id)));
 
  982         dbl_muls3[dbl_id].reset(new Fqk_special_mul_gadget(
 
  985             *g_RR_at_P3s[dbl_id],
 
  987             FMT(annotation_prefix, " dbl_muls3_%zu", dbl_id)));
 
  989         dbl_muls4[dbl_id].reset(new Fqk_special_mul_gadget(
 
  991             (f_id + 1 == f_count ? result : *fs[f_id + 1]),
 
  992             *g_RR_at_P4s[dbl_id],
 
  994             FMT(annotation_prefix, " dbl_muls4_%zu", dbl_id)));
 
  999             addition_steps1[add_id].reset(
 
 1000                 new mnt_miller_loop_add_line_eval<ppT>(
 
 1004                     *prec_Q1.coeffs[prec_id],
 
 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>(
 
 1013                     *prec_Q2.coeffs[prec_id],
 
 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>(
 
 1022                     *prec_Q3.coeffs[prec_id],
 
 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>(
 
 1031                     *prec_Q4.coeffs[prec_id],
 
 1033                     g_RQ_at_P4s[add_id],
 
 1034                     FMT(annotation_prefix, " addition_steps4_%zu", add_id)));
 
 1036             add_muls1[add_id].reset(new Fqk_special_mul_gadget(
 
 1039                 *g_RQ_at_P1s[add_id],
 
 1041                 FMT(annotation_prefix, " add_muls1_%zu", add_id)));
 
 1043             add_muls2[add_id].reset(new Fqk_special_mul_gadget(
 
 1046                 *g_RQ_at_P2s[add_id],
 
 1048                 FMT(annotation_prefix, " add_muls2_%zu", add_id)));
 
 1050             add_muls3[add_id].reset(new Fqk_special_mul_gadget(
 
 1053                 *g_RQ_at_P3s[add_id],
 
 1055                 FMT(annotation_prefix, " add_muls3_%zu", add_id)));
 
 1057             add_muls4[add_id].reset(new Fqk_special_mul_gadget(
 
 1059                 (f_id + 1 == f_count ? result : *fs[f_id + 1]),
 
 1060                 *g_RQ_at_P4s[add_id],
 
 1062                 FMT(annotation_prefix, " add_muls4_%zu", add_id)));
 
 1069 template<typename ppT>
 
 1070 void mnt_e_times_e_times_e_over_e_miller_loop_gadget<
 
 1071     ppT>::generate_r1cs_constraints()
 
 1073     fs[0]->generate_r1cs_equals_const_constraints(FqkT::one());
 
 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();
 
 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();
 
 1099 template<typename ppT>
 
 1100 void mnt_e_times_e_times_e_over_e_miller_loop_gadget<
 
 1101     ppT>::generate_r1cs_witness()
 
 1103     fs[0]->generate_r1cs_witness(FqkT::one());
 
 1109     const auto &loop_count = mnt_pairing_params<ppT>::pairing_loop_count;
 
 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);
 
 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();
 
 1126         dbl_muls1[dbl_id]->generate_r1cs_witness();
 
 1128         dbl_muls2[dbl_id]->generate_r1cs_witness();
 
 1130         dbl_muls3[dbl_id]->generate_r1cs_witness();
 
 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();
 
 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();
 
 1147             add_muls2[add_id]->generate_r1cs_witness();
 
 1149             add_muls3[add_id]->generate_r1cs_witness();
 
 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();
 
 1162 } // namespace libsnark
 
 1164 #endif // LIBSNARK_GADGETLIB1_GADGETS_PAIRING_MNT_MNT_MILLER_LOOP_TCC_