2  *****************************************************************************
 
    4  Implementation of interfaces for final exponentiation gadgets.
 
    6  See weierstrass_final_exponentiation.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_FINAL_EXPONENTIATION_TCC_
 
   15 #define LIBSNARK_GADGETLIB1_GADGETS_PAIRING_MNT_MNT_FINAL_EXPONENTIATION_TCC_
 
   17 #include "libsnark/gadgetlib1/gadgets/basic_gadgets.hpp"
 
   18 #include "libsnark/gadgetlib1/gadgets/pairing/mnt/mnt_pairing_params.hpp"
 
   23 template<typename ppT>
 
   24 mnt4_final_exp_gadget<ppT>::mnt4_final_exp_gadget(
 
   25     protoboard<FieldT> &pb,
 
   26     const Fqk_variable<ppT> &el,
 
   27     const pb_variable<FieldT> &result_is_one,
 
   28     const std::string &annotation_prefix)
 
   29     : gadget<FieldT>(pb, annotation_prefix)
 
   31     , result_is_one(result_is_one)
 
   33     one.reset(new Fqk_variable<ppT>(pb, FMT(annotation_prefix, " one")));
 
   34     el_inv.reset(new Fqk_variable<ppT>(pb, FMT(annotation_prefix, " el_inv")));
 
   35     el_q_3.reset(new Fqk_variable<ppT>(el.Frobenius_map(3)));
 
   37         new Fqk_variable<ppT>(pb, FMT(annotation_prefix, " el_q_3_minus_1")));
 
   38     alpha.reset(new Fqk_variable<ppT>(el_q_3_minus_1->Frobenius_map(1)));
 
   39     beta.reset(new Fqk_variable<ppT>(pb, FMT(annotation_prefix, " beta")));
 
   40     beta_q.reset(new Fqk_variable<ppT>(beta->Frobenius_map(1)));
 
   42     el_inv_q_3.reset(new Fqk_variable<ppT>(el_inv->Frobenius_map(3)));
 
   43     el_inv_q_3_minus_1.reset(new Fqk_variable<ppT>(
 
   44         pb, FMT(annotation_prefix, " el_inv_q_3_minus_1")));
 
   46         new Fqk_variable<ppT>(el_inv_q_3_minus_1->Frobenius_map(1)));
 
   48         new Fqk_variable<ppT>(pb, FMT(annotation_prefix, " inv_beta")));
 
   49     w1.reset(new Fqk_variable<ppT>(pb, FMT(annotation_prefix, " w1")));
 
   50     w0.reset(new Fqk_variable<ppT>(pb, FMT(annotation_prefix, " w0")));
 
   51     result.reset(new Fqk_variable<ppT>(pb, FMT(annotation_prefix, " result")));
 
   53     compute_el_inv.reset(new Fqk_mul_gadget<ppT>(
 
   54         pb, el, *el_inv, *one, FMT(annotation_prefix, " compute_el_inv")));
 
   55     compute_el_q_3_minus_1.reset(new Fqk_mul_gadget<ppT>(
 
   60         FMT(annotation_prefix, " compute_el_q_3_minus_1")));
 
   61     compute_beta.reset(new Fqk_mul_gadget<ppT>(
 
   66         FMT(annotation_prefix, " compute_beta")));
 
   68     compute_el_inv_q_3_minus_1.reset(new Fqk_mul_gadget<ppT>(
 
   73         FMT(annotation_prefix, " compute_el_inv__q_3_minus_1")));
 
   74     compute_inv_beta.reset(new Fqk_mul_gadget<ppT>(
 
   79         FMT(annotation_prefix, " compute_inv_beta")));
 
   81     compute_w1.reset(new exponentiation_gadget<
 
   84                      Fp6_2over3_mul_gadget,
 
   85                      Fp6_2over3_cyclotomic_sqr_gadget,
 
   89         libff::mnt6_final_exponent_last_chunk_w1,
 
   91         FMT(annotation_prefix, " compute_w1")));
 
   93     compute_w0.reset(new exponentiation_gadget<
 
   96                      Fp6_2over3_mul_gadget,
 
   97                      Fp6_2over3_cyclotomic_sqr_gadget,
 
  100         (libff::mnt6_final_exponent_last_chunk_is_w0_neg ? *inv_beta : *beta),
 
  101         libff::mnt6_final_exponent_last_chunk_abs_of_w0,
 
  103         FMT(annotation_prefix, " compute_w0")));
 
  105     compute_result.reset(new Fqk_mul_gadget<ppT>(
 
  106         pb, *w1, *w0, *result, FMT(annotation_prefix, " compute_result")));
 
  109 template<typename ppT>
 
  110 void mnt4_final_exp_gadget<ppT>::generate_r1cs_constraints()
 
  112     one->generate_r1cs_equals_const_constraints(
 
  113         libff::Fqk<other_curve<ppT>>::one());
 
  115     compute_el_inv->generate_r1cs_constraints();
 
  116     compute_el_q_3_minus_1->generate_r1cs_constraints();
 
  117     compute_beta->generate_r1cs_constraints();
 
  119     compute_el_inv_q_3_minus_1->generate_r1cs_constraints();
 
  120     compute_inv_beta->generate_r1cs_constraints();
 
  122     compute_w0->generate_r1cs_constraints();
 
  123     compute_w1->generate_r1cs_constraints();
 
  124     compute_result->generate_r1cs_constraints();
 
  126     generate_boolean_r1cs_constraint<FieldT>(
 
  129         FMT(this->annotation_prefix, " result_is_one"));
 
  130     this->pb.add_r1cs_constraint(
 
  131         r1cs_constraint<FieldT>(result_is_one, 1 - result->c0.c0, 0),
 
  133     this->pb.add_r1cs_constraint(
 
  134         r1cs_constraint<FieldT>(result_is_one, result->c0.c1, 0),
 
  136     this->pb.add_r1cs_constraint(
 
  137         r1cs_constraint<FieldT>(result_is_one, result->c0.c2, 0),
 
  139     this->pb.add_r1cs_constraint(
 
  140         r1cs_constraint<FieldT>(result_is_one, result->c1.c0, 0),
 
  142     this->pb.add_r1cs_constraint(
 
  143         r1cs_constraint<FieldT>(result_is_one, result->c1.c1, 0),
 
  145     this->pb.add_r1cs_constraint(
 
  146         r1cs_constraint<FieldT>(result_is_one, result->c1.c2, 0),
 
  150 template<typename ppT> void mnt4_final_exp_gadget<ppT>::generate_r1cs_witness()
 
  152     one->generate_r1cs_witness(libff::Fqk<other_curve<ppT>>::one());
 
  153     el_inv->generate_r1cs_witness(el.get_element().inverse());
 
  155     compute_el_inv->generate_r1cs_witness();
 
  157     compute_el_q_3_minus_1->generate_r1cs_witness();
 
  159     compute_beta->generate_r1cs_witness();
 
  162     el_inv_q_3->evaluate();
 
  163     compute_el_inv_q_3_minus_1->generate_r1cs_witness();
 
  164     inv_alpha->evaluate();
 
  165     compute_inv_beta->generate_r1cs_witness();
 
  167     compute_w0->generate_r1cs_witness();
 
  168     compute_w1->generate_r1cs_witness();
 
  169     compute_result->generate_r1cs_witness();
 
  171     this->pb.val(result_is_one) =
 
  172         (result->get_element() == one->get_element() ? FieldT::one()
 
  176 template<typename ppT>
 
  177 mnt6_final_exp_gadget<ppT>::mnt6_final_exp_gadget(
 
  178     protoboard<FieldT> &pb,
 
  179     const Fqk_variable<ppT> &el,
 
  180     const pb_variable<FieldT> &result_is_one,
 
  181     const std::string &annotation_prefix)
 
  182     : gadget<FieldT>(pb, annotation_prefix)
 
  184     , result_is_one(result_is_one)
 
  186     one.reset(new Fqk_variable<ppT>(pb, FMT(annotation_prefix, " one")));
 
  187     el_inv.reset(new Fqk_variable<ppT>(pb, FMT(annotation_prefix, " el_inv")));
 
  188     el_q_2.reset(new Fqk_variable<ppT>(el.Frobenius_map(2)));
 
  189     el_q_2_minus_1.reset(
 
  190         new Fqk_variable<ppT>(pb, FMT(annotation_prefix, " el_q_2_minus_1")));
 
  191     el_q_3_minus_q.reset(
 
  192         new Fqk_variable<ppT>(el_q_2_minus_1->Frobenius_map(1)));
 
  193     el_inv_q_2.reset(new Fqk_variable<ppT>(el_inv->Frobenius_map(2)));
 
  194     el_inv_q_2_minus_1.reset(new Fqk_variable<ppT>(
 
  195         pb, FMT(annotation_prefix, " el_inv_q_2_minus_1")));
 
  196     w1.reset(new Fqk_variable<ppT>(pb, FMT(annotation_prefix, " w1")));
 
  197     w0.reset(new Fqk_variable<ppT>(pb, FMT(annotation_prefix, " w0")));
 
  198     result.reset(new Fqk_variable<ppT>(pb, FMT(annotation_prefix, " result")));
 
  200     compute_el_inv.reset(new Fqk_mul_gadget<ppT>(
 
  201         pb, el, *el_inv, *one, FMT(annotation_prefix, " compute_el_inv")));
 
  202     compute_el_q_2_minus_1.reset(new Fqk_mul_gadget<ppT>(
 
  207         FMT(annotation_prefix, " compute_el_q_2_minus_1")));
 
  208     compute_el_inv_q_2_minus_1.reset(new Fqk_mul_gadget<ppT>(
 
  213         FMT(annotation_prefix, " compute_el_inv_q_2_minus_1")));
 
  215     compute_w1.reset(new exponentiation_gadget<
 
  219                      Fp4_cyclotomic_sqr_gadget,
 
  220                      libff::mnt4_q_limbs>(
 
  223         libff::mnt4_final_exponent_last_chunk_w1,
 
  225         FMT(annotation_prefix, " compute_w1")));
 
  226     compute_w0.reset(new exponentiation_gadget<
 
  230                      Fp4_cyclotomic_sqr_gadget,
 
  231                      libff::mnt4_q_limbs>(
 
  233         (libff::mnt4_final_exponent_last_chunk_is_w0_neg ? *el_inv_q_2_minus_1
 
  235         libff::mnt4_final_exponent_last_chunk_abs_of_w0,
 
  237         FMT(annotation_prefix, " compute_w0")));
 
  238     compute_result.reset(new Fqk_mul_gadget<ppT>(
 
  239         pb, *w1, *w0, *result, FMT(annotation_prefix, " compute_result")));
 
  242 template<typename ppT>
 
  243 void mnt6_final_exp_gadget<ppT>::generate_r1cs_constraints()
 
  245     one->generate_r1cs_equals_const_constraints(
 
  246         libff::Fqk<other_curve<ppT>>::one());
 
  248     compute_el_inv->generate_r1cs_constraints();
 
  249     compute_el_q_2_minus_1->generate_r1cs_constraints();
 
  250     compute_el_inv_q_2_minus_1->generate_r1cs_constraints();
 
  251     compute_w1->generate_r1cs_constraints();
 
  252     compute_w0->generate_r1cs_constraints();
 
  253     compute_result->generate_r1cs_constraints();
 
  255     generate_boolean_r1cs_constraint<FieldT>(
 
  258         FMT(this->annotation_prefix, " result_is_one"));
 
  259     this->pb.add_r1cs_constraint(
 
  260         r1cs_constraint<FieldT>(result_is_one, 1 - result->c0.c0, 0),
 
  262     this->pb.add_r1cs_constraint(
 
  263         r1cs_constraint<FieldT>(result_is_one, result->c0.c1, 0),
 
  265     this->pb.add_r1cs_constraint(
 
  266         r1cs_constraint<FieldT>(result_is_one, result->c1.c0, 0),
 
  268     this->pb.add_r1cs_constraint(
 
  269         r1cs_constraint<FieldT>(result_is_one, result->c1.c1, 0),
 
  273 template<typename ppT> void mnt6_final_exp_gadget<ppT>::generate_r1cs_witness()
 
  275     one->generate_r1cs_witness(libff::Fqk<other_curve<ppT>>::one());
 
  276     el_inv->generate_r1cs_witness(el.get_element().inverse());
 
  278     compute_el_inv->generate_r1cs_witness();
 
  280     compute_el_q_2_minus_1->generate_r1cs_witness();
 
  281     el_q_3_minus_q->evaluate();
 
  282     el_inv_q_2->evaluate();
 
  283     compute_el_inv_q_2_minus_1->generate_r1cs_witness();
 
  284     compute_w1->generate_r1cs_witness();
 
  285     compute_w0->generate_r1cs_witness();
 
  286     compute_result->generate_r1cs_witness();
 
  288     this->pb.val(result_is_one) =
 
  289         (result->get_element() == one->get_element() ? FieldT::one()
 
  293 } // namespace libsnark
 
  295 #endif // LIBSNARK_GADGETLIB1_GADGETS_PAIRING_MNT_MNT_FINAL_EXPONENTIATION_TCC_