2  *****************************************************************************
 
    3  * @author     This file is part of libsnark, developed by Clearmatics Ltd
 
    4  *             (originally developed by SCIPR Lab) and contributors
 
    6  * @copyright  MIT license (see LICENSE file)
 
    7  *****************************************************************************/
 
    9 #ifndef LIBSNARK_GADGETLIB1_GADGETS_PAIRING_BW6_761_BLS12_377_BLS12_377_FINAL_EXPONENTIATION_TCC_
 
   10 #define LIBSNARK_GADGETLIB1_GADGETS_PAIRING_BW6_761_BLS12_377_BLS12_377_FINAL_EXPONENTIATION_TCC_
 
   12 #include "libsnark/gadgetlib1/gadgets/basic_gadgets.hpp"
 
   13 #include "libsnark/gadgetlib1/gadgets/pairing/bw6_761_bls12_377/bls12_377_final_exponentiation.hpp"
 
   18 // bls12_377_final_exp_first_part_gadget methods
 
   20 template<typename ppT>
 
   21 bls12_377_final_exp_first_part_gadget<ppT>::
 
   22     bls12_377_final_exp_first_part_gadget(
 
   23         protoboard<FieldT> &pb,
 
   24         const Fp12_2over3over2_variable<FqkT> &in,
 
   25         const Fp12_2over3over2_variable<FqkT> &result,
 
   26         const std::string &annotation_prefix)
 
   27     : gadget<FieldT>(pb, annotation_prefix)
 
   32           Fp12_2over3over2_variable<FqkT>(pb, FMT(annotation_prefix, " B")),
 
   33           FMT(annotation_prefix, " _B"))
 
   36           in.frobenius_map(6), // _A
 
   38           Fp12_2over3over2_variable<FqkT>(pb, FMT(annotation_prefix, " C")),
 
   39           FMT(annotation_prefix, " _C"))
 
   42           _compute_C.result().frobenius_map(2), // _D
 
   45           FMT(annotation_prefix, " _D_times_C"))
 
   49 template<typename ppT>
 
   50 const Fp12_2over3over2_variable<libff::Fqk<other_curve<ppT>>>
 
   51     &bls12_377_final_exp_first_part_gadget<ppT>::result() const
 
   56 template<typename ppT>
 
   57 void bls12_377_final_exp_first_part_gadget<ppT>::generate_r1cs_constraints()
 
   59     _compute_B.generate_r1cs_constraints();
 
   60     _compute_C.generate_r1cs_constraints();
 
   61     _compute_D_times_C.generate_r1cs_constraints();
 
   64 template<typename ppT>
 
   65 void bls12_377_final_exp_first_part_gadget<ppT>::generate_r1cs_witness()
 
   67     _compute_B.generate_r1cs_witness();
 
   68     _compute_C._A.evaluate();
 
   69     _compute_C.generate_r1cs_witness();
 
   70     _compute_D_times_C._A.evaluate();
 
   71     _compute_D_times_C.generate_r1cs_witness();
 
   74 // bls12_377_exp_by_z_gadget methods
 
   76 template<typename ppT>
 
   77 bls12_377_exp_by_z_gadget<ppT>::bls12_377_exp_by_z_gadget(
 
   78     protoboard<FieldT> &pb,
 
   79     const Fp12_2over3over2_variable<FqkT> &in,
 
   80     const Fp12_2over3over2_variable<FqkT> &result,
 
   81     const std::string &annotation_prefix)
 
   82     : gadget<FieldT>(pb, annotation_prefix), _result(result)
 
   84     // There is some complexity in ensuring that the result uses _result as an
 
   85     // output variable. If bls12_377_final_exponent_is_z_neg, we perform all
 
   86     // square and multiplies into intermediate variables and then unitary
 
   87     // inverse into _result. Otherwise, care must be taken during the final
 
   88     // iteration so that _result holds the output from the final multiply.
 
   90     if (libff::bls12_377_final_exponent_is_z_neg) {
 
   91         initialize_z_neg(pb, in, annotation_prefix);
 
   93         initialize_z_pos(pb, in, annotation_prefix);
 
   97 template<typename ppT>
 
   98 void bls12_377_exp_by_z_gadget<ppT>::initialize_z_neg(
 
   99     protoboard<FieldT> &pb,
 
  100     const Fp12_2over3over2_variable<FqkT> &in,
 
  101     const std::string &annotation_prefix)
 
  103     const Fp12_2over3over2_variable<FqkT> *res = ∈
 
  105     // Iterate through all bits, then perform a unitary_inverse into result
 
  107     const size_t num_bits = libff::bls12_377_final_exponent_z.num_bits();
 
  108     for (size_t bit_idx = num_bits - 1; bit_idx > 0; --bit_idx) {
 
  109         // result <- result.cyclotomic_squared()
 
  111             std::shared_ptr<cyclotomic_square>(new cyclotomic_square(
 
  114                 Fp12_2over3over2_variable<FqkT>(
 
  115                     pb, FMT(annotation_prefix, " res^2")),
 
  116                 FMT(annotation_prefix, " _squares[%zu]", _squares.size()))));
 
  117         res = &(_squares.back()->result());
 
  119         if (libff::bls12_377_final_exponent_z.test_bit(bit_idx - 1)) {
 
  120             // result <- result * elt
 
  121             _multiplies.push_back(std::shared_ptr<multiply>(new multiply(
 
  125                 Fp12_2over3over2_variable<FqkT>(
 
  126                     pb, FMT(annotation_prefix, " res*in")),
 
  127                 FMT(annotation_prefix,
 
  129                     _multiplies.size()))));
 
  130             res = &(_multiplies.back()->result());
 
  134     _inverse = std::shared_ptr<unitary_inverse>(new unitary_inverse(
 
  135         pb, *res, _result, FMT(annotation_prefix, " res.inv")));
 
  138 template<typename ppT>
 
  139 void bls12_377_exp_by_z_gadget<ppT>::initialize_z_pos(
 
  140     protoboard<FieldT> &pb,
 
  141     const Fp12_2over3over2_variable<FqkT> &in,
 
  142     const std::string &annotation_prefix)
 
  144     const Fp12_2over3over2_variable<FqkT> *res = ∈
 
  146     // Iterate through all bits, leaving the last one as a special case.
 
  147     const size_t num_bits = libff::bls12_377_final_exponent_z.num_bits();
 
  148     for (size_t bit_idx = num_bits - 1; bit_idx > 1; --bit_idx) {
 
  149         // result <- result.cyclotomic_squared()
 
  151             std::shared_ptr<cyclotomic_square>(new cyclotomic_square(
 
  154                 Fp12_2over3over2_variable<FqkT>(
 
  155                     pb, FMT(annotation_prefix, " res^2")),
 
  156                 FMT(annotation_prefix, " _squares[%zu]", _squares.size()))));
 
  157         res = &(_squares.back()->result());
 
  159         if (libff::bls12_377_final_exponent_z.test_bit(bit_idx - 1)) {
 
  160             // result <- result * elt
 
  161             _multiplies.push_back(std::shared_ptr<multiply>(new multiply(
 
  165                 Fp12_2over3over2_variable<FqkT>(
 
  166                     pb, FMT(annotation_prefix, " res*in")),
 
  167                 FMT(annotation_prefix,
 
  169                     _multiplies.size()))));
 
  170             res = &(_multiplies.back()->result());
 
  174     // Write the output of the final iteration to result.
 
  175     assert(libff::bls12_377_final_exponent_z.test_bit(0));
 
  176     _squares.push_back(std::shared_ptr<cyclotomic_square>(new cyclotomic_square(
 
  179         Fp12_2over3over2_variable<FqkT>(pb, FMT(annotation_prefix, "res^2")),
 
  180         FMT(annotation_prefix, " _squares[%zu]", _squares.size()))));
 
  181     res = &(_squares.back()->result());
 
  183     _multiplies.push_back(std::shared_ptr<multiply>(new multiply(
 
  188         FMT(annotation_prefix, " _multiplies[%zu]", _multiplies.size()))));
 
  191 template<typename ppT>
 
  192 const Fp12_2over3over2_variable<libff::Fqk<other_curve<ppT>>>
 
  193     &bls12_377_exp_by_z_gadget<ppT>::result() const
 
  198 template<typename ppT>
 
  199 void bls12_377_exp_by_z_gadget<ppT>::generate_r1cs_constraints()
 
  203     const size_t num_bits = libff::bls12_377_final_exponent_z.num_bits();
 
  204     for (size_t bit_idx = num_bits - 1; bit_idx > 0; --bit_idx) {
 
  205         _squares[sqr_idx++]->generate_r1cs_constraints();
 
  206         if (libff::bls12_377_final_exponent_z.test_bit(bit_idx - 1)) {
 
  207             _multiplies[mul_idx++]->generate_r1cs_constraints();
 
  212         _inverse->generate_r1cs_constraints();
 
  216 template<typename ppT>
 
  217 void bls12_377_exp_by_z_gadget<ppT>::generate_r1cs_witness()
 
  221     const size_t num_bits = libff::bls12_377_final_exponent_z.num_bits();
 
  222     for (size_t bit_idx = num_bits - 1; bit_idx > 0; --bit_idx) {
 
  223         _squares[sqr_idx++]->generate_r1cs_witness();
 
  224         if (libff::bls12_377_final_exponent_z.test_bit(bit_idx - 1)) {
 
  225             _multiplies[mul_idx++]->generate_r1cs_witness();
 
  230         _inverse->generate_r1cs_witness();
 
  234 // bls12_377_final_exp_last_part_gadget methods
 
  236 template<typename ppT>
 
  237 bls12_377_final_exp_last_part_gadget<ppT>::bls12_377_final_exp_last_part_gadget(
 
  238     protoboard<FieldT> &pb,
 
  239     const Fp12_2over3over2_variable<FqkT> &in,
 
  240     const Fp12_2over3over2_variable<FqkT> &result,
 
  241     const std::string &annotation_prefix)
 
  242     : gadget<FieldT>(pb, annotation_prefix)
 
  245     , _compute_in_squared(
 
  248           Fp12_2over3over2_variable<FqkT>(
 
  249               pb, FMT(annotation_prefix, " in_squared")),
 
  250           FMT(annotation_prefix, " _compute_in_squared"))
 
  255           Fp12_2over3over2_variable<FqkT>(pb, FMT(annotation_prefix, " B")),
 
  256           FMT(annotation_prefix, " _compute_B"))
 
  261           Fp12_2over3over2_variable<FqkT>(pb, FMT(annotation_prefix, " C")),
 
  262           FMT(annotation_prefix, " _compute_C"))
 
  266           _compute_in_squared.result().unitary_inverse(), // _A
 
  268           Fp12_2over3over2_variable<FqkT>(pb, FMT(annotation_prefix, " D")),
 
  269           FMT(annotation_prefix, " _compute_D"))
 
  274           Fp12_2over3over2_variable<FqkT>(pb, FMT(annotation_prefix, " E")),
 
  275           FMT(annotation_prefix, " _compute_E"))
 
  280           Fp12_2over3over2_variable<FqkT>(pb, FMT(annotation_prefix, " F")),
 
  281           FMT(annotation_prefix, " _compute_F"))
 
  286           Fp12_2over3over2_variable<FqkT>(pb, FMT(annotation_prefix, " G")),
 
  287           FMT(annotation_prefix, " _compute_G"))
 
  293           Fp12_2over3over2_variable<FqkT>(pb, FMT(annotation_prefix, " H")),
 
  294           FMT(annotation_prefix, " _comptue_H"))
 
  295     // I = [z^5-2z^4+2z^2]
 
  299           Fp12_2over3over2_variable<FqkT>(pb, FMT(annotation_prefix, " I")),
 
  300           FMT(annotation_prefix, " _compute_I"))
 
  302     // K = [z^5-2z^4+2z^2-z+2]
 
  306           _compute_D.result().unitary_inverse(), // _J
 
  307           Fp12_2over3over2_variable<FqkT>(pb, FMT(annotation_prefix, " K")),
 
  308           FMT(annotation_prefix, " _compute_K"))
 
  309     // L = [z^5-2z^4+2z^2-z+3] = [\lambda_0]
 
  314           Fp12_2over3over2_variable<FqkT>(pb, FMT(annotation_prefix, " L")),
 
  315           FMT(annotation_prefix, " _compute_L"))
 
  317     // N = [z^2-2z+1] = [\lambda_3]
 
  322           Fp12_2over3over2_variable<FqkT>(pb, FMT(annotation_prefix, " N")),
 
  323           FMT(annotation_prefix, " _compute_N"))
 
  324     // O = [(z^2-2z+1) * (q^3)]
 
  325     // P = [z^4-2z^3+2z-1] = [\lambda_1]
 
  329           in.unitary_inverse(), // _M
 
  330           Fp12_2over3over2_variable<FqkT>(pb, FMT(annotation_prefix, " P")),
 
  331           FMT(annotation_prefix, " _compute_P"))
 
  332     // Q = [(z^4-2z^3+2z-1) * q]
 
  333     // R = [z^3-2z^2+z] = [\lambda_2]
 
  338           Fp12_2over3over2_variable<FqkT>(pb, FMT(annotation_prefix, " R")),
 
  339           FMT(annotation_prefix, " _compute_R"))
 
  340     // S = [(z^3-2z^2+z) * (q^2)]
 
  341     // T = [(z^2-2z+1) * (q^3) + (z^3-2z^2+z) * (q^2)]
 
  344           _compute_N.result().frobenius_map(3), // _O
 
  345           _compute_R.result().frobenius_map(2), // _S
 
  346           Fp12_2over3over2_variable<FqkT>(pb, FMT(annotation_prefix, " T")),
 
  347           FMT(annotation_prefix, " _compute_T"))
 
  348     // U = [(z^2-2z+1) * (q^3) + (z^3-2z^2+z) * (q^2) + (z^4-2z^3+2z-1) * q]
 
  352           _compute_P.result().frobenius_map(1), // _Q
 
  353           Fp12_2over3over2_variable<FqkT>(pb, FMT(annotation_prefix, " U")),
 
  354           FMT(annotation_prefix, " _compute_U"))
 
  355     // result = [(z^2-2z+1) * (q^3) + (z^3-2z^2+z) * (q^2) + (z^4-2z^3+2z-1) * q
 
  356     //          + z^5-2z^4+2z^2-z+3]
 
  357     //        = [(p^4 - p^2 + 1)/r].
 
  358     , _compute_U_times_L(
 
  363           FMT(annotation_prefix, " _compute_U_times_L"))
 
  367 template<typename ppT>
 
  368 const Fp12_2over3over2_variable<libff::Fqk<other_curve<ppT>>>
 
  369     &bls12_377_final_exp_last_part_gadget<ppT>::result() const
 
  374 template<typename ppT>
 
  375 void bls12_377_final_exp_last_part_gadget<ppT>::generate_r1cs_constraints()
 
  377     _compute_in_squared.generate_r1cs_constraints();
 
  378     _compute_B.generate_r1cs_constraints();
 
  379     _compute_C.generate_r1cs_constraints();
 
  380     _compute_D.generate_r1cs_constraints();
 
  381     _compute_E.generate_r1cs_constraints();
 
  382     _compute_F.generate_r1cs_constraints();
 
  383     _compute_G.generate_r1cs_constraints();
 
  384     _compute_H.generate_r1cs_constraints();
 
  385     _compute_I.generate_r1cs_constraints();
 
  386     _compute_K.generate_r1cs_constraints();
 
  387     _compute_L.generate_r1cs_constraints();
 
  388     _compute_N.generate_r1cs_constraints();
 
  389     _compute_P.generate_r1cs_constraints();
 
  390     _compute_R.generate_r1cs_constraints();
 
  391     _compute_T.generate_r1cs_constraints();
 
  392     _compute_U.generate_r1cs_constraints();
 
  393     _compute_U_times_L.generate_r1cs_constraints();
 
  396 template<typename ppT>
 
  397 void bls12_377_final_exp_last_part_gadget<ppT>::generate_r1cs_witness()
 
  399     _compute_in_squared.generate_r1cs_witness();
 
  400     _compute_B.generate_r1cs_witness();
 
  401     _compute_C.generate_r1cs_witness();
 
  402     _compute_D._A.evaluate();
 
  403     _compute_D.generate_r1cs_witness();
 
  404     _compute_E.generate_r1cs_witness();
 
  405     _compute_F.generate_r1cs_witness();
 
  406     _compute_G.generate_r1cs_witness();
 
  407     _compute_H.generate_r1cs_witness();
 
  408     _compute_I.generate_r1cs_witness();
 
  409     _compute_K._B.evaluate();
 
  410     _compute_K.generate_r1cs_witness();
 
  411     _compute_L.generate_r1cs_witness();
 
  412     _compute_N._A.evaluate();
 
  413     _compute_N.generate_r1cs_witness();
 
  414     _compute_P._B.evaluate();
 
  415     _compute_P.generate_r1cs_witness();
 
  416     _compute_R.generate_r1cs_witness();
 
  417     _compute_T._A.evaluate();
 
  418     _compute_T._B.evaluate();
 
  419     _compute_T.generate_r1cs_witness();
 
  420     _compute_U._B.evaluate();
 
  421     _compute_U.generate_r1cs_witness();
 
  422     _compute_U_times_L.generate_r1cs_witness();
 
  425 // bls12_377_final_exp_gadget methods
 
  427 template<typename ppT>
 
  428 bls12_377_final_exp_gadget<ppT>::bls12_377_final_exp_gadget(
 
  429     protoboard<libff::Fr<ppT>> &pb,
 
  430     const Fp12_2over3over2_variable<FqkT> &el,
 
  431     const pb_variable<FieldT> &result_is_one,
 
  432     const std::string &annotation_prefix)
 
  433     : gadget<FieldT>(pb, annotation_prefix)
 
  434     , _compute_first_part(
 
  437           Fqk_variable<ppT>(pb, FMT(annotation_prefix, " first_part")),
 
  438           FMT(annotation_prefix, " _compute_first_part"))
 
  439     , _compute_last_part(
 
  441           _compute_first_part.result(),
 
  442           Fqk_variable<ppT>(pb, FMT(annotation_prefix, "last_part")),
 
  443           FMT(annotation_prefix, " _compute_last_part"))
 
  444     , _result_is_one(result_is_one)
 
  448 template<typename ppT>
 
  449 void bls12_377_final_exp_gadget<ppT>::generate_r1cs_constraints()
 
  451     _compute_first_part.generate_r1cs_constraints();
 
  452     _compute_last_part.generate_r1cs_constraints();
 
  454     // Constrain result_is_one to be 0 or 1.
 
  455     generate_boolean_r1cs_constraint<FieldT>(
 
  458         FMT(this->annotation_prefix, " result_is_one_boolean"));
 
  460     // Use the value of result_is_one to enable / disable the constraints on
 
  461     // the 12 components of the result of the final exponentiation in Fq12.
 
  462     Fqk_variable<ppT> result = _compute_last_part.result();
 
  463     this->pb.add_r1cs_constraint(
 
  464         r1cs_constraint<FieldT>(_result_is_one, 1 - result._c0._c0.c0, 0),
 
  466     this->pb.add_r1cs_constraint(
 
  467         r1cs_constraint<FieldT>(_result_is_one, result._c0._c0.c1, 0),
 
  469     this->pb.add_r1cs_constraint(
 
  470         r1cs_constraint<FieldT>(_result_is_one, result._c0._c1.c0, 0),
 
  472     this->pb.add_r1cs_constraint(
 
  473         r1cs_constraint<FieldT>(_result_is_one, result._c0._c1.c1, 0),
 
  475     this->pb.add_r1cs_constraint(
 
  476         r1cs_constraint<FieldT>(_result_is_one, result._c0._c2.c0, 0),
 
  478     this->pb.add_r1cs_constraint(
 
  479         r1cs_constraint<FieldT>(_result_is_one, result._c0._c2.c1, 0),
 
  481     this->pb.add_r1cs_constraint(
 
  482         r1cs_constraint<FieldT>(_result_is_one, result._c1._c0.c0, 0),
 
  484     this->pb.add_r1cs_constraint(
 
  485         r1cs_constraint<FieldT>(_result_is_one, result._c1._c0.c1, 0),
 
  487     this->pb.add_r1cs_constraint(
 
  488         r1cs_constraint<FieldT>(_result_is_one, result._c1._c1.c0, 0),
 
  490     this->pb.add_r1cs_constraint(
 
  491         r1cs_constraint<FieldT>(_result_is_one, result._c1._c1.c1, 0),
 
  493     this->pb.add_r1cs_constraint(
 
  494         r1cs_constraint<FieldT>(_result_is_one, result._c1._c2.c0, 0),
 
  496     this->pb.add_r1cs_constraint(
 
  497         r1cs_constraint<FieldT>(_result_is_one, result._c1._c2.c1, 0),
 
  501 template<typename ppT>
 
  502 void bls12_377_final_exp_gadget<ppT>::generate_r1cs_witness()
 
  504     _compute_first_part.generate_r1cs_witness();
 
  505     _compute_last_part.generate_r1cs_witness();
 
  507     const FqkT result_val = _compute_last_part.result().get_element();
 
  508     this->pb.val(_result_is_one) =
 
  509         (result_val == FqkT::one()) ? FieldT::one() : FieldT::zero();
 
  512 } // namespace libsnark
 
  514 #endif // LIBSNARK_GADGETLIB1_GADGETS_PAIRING_BW6_761_BLS12_377_BLS12_377_FINAL_EXPONENTIATION_TCC_