2  *****************************************************************************
 
    4  Implementation of interfaces for G2 gadgets.
 
    6  See weierstrass_g2_gadgets.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 WEIERSTRASS_G2_GADGET_TCC_
 
   15 #define WEIERSTRASS_G2_GADGET_TCC_
 
   17 #include <libff/algebra/scalar_multiplication/wnaf.hpp>
 
   22 template<typename ppT>
 
   23 G2_variable<ppT>::G2_variable(
 
   24     protoboard<FieldT> &pb, const std::string &annotation_prefix)
 
   25     : gadget<FieldT>(pb, annotation_prefix)
 
   27     X.reset(new Fqe_variable<ppT>(pb, FMT(annotation_prefix, " X")));
 
   28     Y.reset(new Fqe_variable<ppT>(pb, FMT(annotation_prefix, " Y")));
 
   30     all_vars.insert(all_vars.end(), X->all_vars.begin(), X->all_vars.end());
 
   31     all_vars.insert(all_vars.end(), Y->all_vars.begin(), Y->all_vars.end());
 
   34 template<typename ppT>
 
   35 G2_variable<ppT>::G2_variable(
 
   36     protoboard<FieldT> &pb,
 
   37     const libff::G2<other_curve<ppT>> &Q,
 
   38     const std::string &annotation_prefix)
 
   39     : gadget<FieldT>(pb, annotation_prefix)
 
   41     libff::G2<other_curve<ppT>> Q_copy = Q;
 
   42     Q_copy.to_affine_coordinates();
 
   44     X.reset(new Fqe_variable<ppT>(pb, Q_copy.X, FMT(annotation_prefix, " X")));
 
   45     Y.reset(new Fqe_variable<ppT>(pb, Q_copy.Y, FMT(annotation_prefix, " Y")));
 
   47     all_vars.insert(all_vars.end(), X->all_vars.begin(), X->all_vars.end());
 
   48     all_vars.insert(all_vars.end(), Y->all_vars.begin(), Y->all_vars.end());
 
   51 template<typename ppT>
 
   52 G2_variable<ppT>::G2_variable(
 
   53     protoboard<FieldT> &pb,
 
   54     const Fqe_variable<ppT> &X_coord,
 
   55     const Fqe_variable<ppT> &Y_coord,
 
   56     const std::string &annotation_prefix)
 
   57     : gadget<FieldT>(pb, annotation_prefix)
 
   58     , X(new Fqe_variable<ppT>(X_coord))
 
   59     , Y(new Fqe_variable<ppT>(Y_coord))
 
   61     all_vars.insert(all_vars.end(), X->all_vars.begin(), X->all_vars.end());
 
   62     all_vars.insert(all_vars.end(), Y->all_vars.begin(), Y->all_vars.end());
 
   65 template<typename ppT> G2_variable<ppT> G2_variable<ppT>::operator-() const
 
   67     return G2_variable<ppT>(
 
   68         this->pb, *X, -(*Y), FMT(this->annotation_prefix, " negative"));
 
   71 template<typename ppT>
 
   72 void G2_variable<ppT>::generate_r1cs_witness(
 
   73     const libff::G2<other_curve<ppT>> &Q)
 
   75     libff::G2<other_curve<ppT>> Qcopy = Q;
 
   76     Qcopy.to_affine_coordinates();
 
   78     X->generate_r1cs_witness(Qcopy.X);
 
   79     Y->generate_r1cs_witness(Qcopy.Y);
 
   82 template<typename ppT>
 
   83 libff::G2<other_curve<ppT>> G2_variable<ppT>::get_element() const
 
   85     using nppT = other_curve<ppT>;
 
   86     return libff::G2<nppT>(
 
   89         libff::G2<nppT>::twist_field::one());
 
   92 template<typename ppT> size_t G2_variable<ppT>::size_in_bits()
 
   94     return 2 * Fqe_variable<ppT>::size_in_bits();
 
   97 template<typename ppT> size_t G2_variable<ppT>::num_variables()
 
   99     return 2 * Fqe_variable<ppT>::num_variables();
 
  102 template<typename ppT>
 
  103 G2_variable_selector_gadget<ppT>::G2_variable_selector_gadget(
 
  104     protoboard<Field> &pb,
 
  105     const pb_linear_combination<Field> &selector,
 
  106     const G2_variable<ppT> &zero_case,
 
  107     const G2_variable<ppT> &one_case,
 
  108     const G2_variable<ppT> &result,
 
  109     const std::string &annotation_prefix)
 
  110     : gadget<Field>(pb, annotation_prefix)
 
  112     , zero_case(zero_case)
 
  117           *one_case.X - *zero_case.X,
 
  119           *result.X - *zero_case.X,
 
  120           FMT(annotation_prefix, " mul_select_X"))
 
  123           *one_case.Y - *zero_case.Y,
 
  125           *result.Y - *zero_case.Y,
 
  126           FMT(annotation_prefix, " mul_select_Y"))
 
  130 template<typename ppT>
 
  131 void G2_variable_selector_gadget<ppT>::generate_r1cs_constraints()
 
  133     mul_select_X.generate_r1cs_constraints();
 
  134     mul_select_Y.generate_r1cs_constraints();
 
  137 template<typename ppT>
 
  138 void G2_variable_selector_gadget<ppT>::generate_r1cs_witness()
 
  140     protoboard<Field> &pb = this->pb;
 
  141     selector.evaluate(pb);
 
  143     zero_case.X->evaluate();
 
  144     zero_case.Y->evaluate();
 
  145     one_case.X->evaluate();
 
  146     one_case.Y->evaluate();
 
  147     mul_select_X.generate_r1cs_witness();
 
  148     mul_select_Y.generate_r1cs_witness();
 
  150     if (pb.lc_val(selector) == Field::one()) {
 
  151         result.generate_r1cs_witness(one_case.get_element());
 
  153         result.generate_r1cs_witness(zero_case.get_element());
 
  157 template<typename ppT>
 
  158 G2_checker_gadget<ppT>::G2_checker_gadget(
 
  159     protoboard<FieldT> &pb,
 
  160     const G2_variable<ppT> &Q,
 
  161     const std::string &annotation_prefix)
 
  162     : gadget<FieldT>(pb, annotation_prefix), Q(Q)
 
  165         new Fqe_variable<ppT>(pb, FMT(annotation_prefix, " Xsquared")));
 
  167         new Fqe_variable<ppT>(pb, FMT(annotation_prefix, " Ysquared")));
 
  169     compute_Xsquared.reset(new Fqe_sqr_gadget<ppT>(
 
  170         pb, *(Q.X), *Xsquared, FMT(annotation_prefix, " compute_Xsquared")));
 
  171     compute_Ysquared.reset(new Fqe_sqr_gadget<ppT>(
 
  172         pb, *(Q.Y), *Ysquared, FMT(annotation_prefix, " compute_Ysquared")));
 
  174     Xsquared_plus_a.reset(new Fqe_variable<ppT>(
 
  175         (*Xsquared) + libff::G2<other_curve<ppT>>::coeff_a));
 
  176     Ysquared_minus_b.reset(new Fqe_variable<ppT>(
 
  177         (*Ysquared) + (-libff::G2<other_curve<ppT>>::coeff_b)));
 
  179     curve_equation.reset(new Fqe_mul_gadget<ppT>(
 
  184         FMT(annotation_prefix, " curve_equation")));
 
  187 template<typename ppT> void G2_checker_gadget<ppT>::generate_r1cs_constraints()
 
  189     compute_Xsquared->generate_r1cs_constraints();
 
  190     compute_Ysquared->generate_r1cs_constraints();
 
  191     curve_equation->generate_r1cs_constraints();
 
  194 template<typename ppT> void G2_checker_gadget<ppT>::generate_r1cs_witness()
 
  196     compute_Xsquared->generate_r1cs_witness();
 
  197     compute_Ysquared->generate_r1cs_witness();
 
  198     Xsquared_plus_a->evaluate();
 
  199     curve_equation->generate_r1cs_witness();
 
  202 template<typename wppT>
 
  203 G2_add_gadget<wppT>::G2_add_gadget(
 
  204     protoboard<libff::Fr<wppT>> &pb,
 
  205     const G2_variable<wppT> &A,
 
  206     const G2_variable<wppT> &B,
 
  207     const G2_variable<wppT> &result,
 
  208     const std::string &annotation_prefix)
 
  209     : gadget<libff::Fr<wppT>>(pb, annotation_prefix)
 
  213     , lambda(pb, FMT(annotation_prefix, " lambda"))
 
  214     // lambda = (By - Ay) / (Bx - Ax)
 
  215     // <=>  lambda * (Bx - Ax) = By - Ay
 
  221           FMT(annotation_prefix, " lambda_constraint"))
 
  222     // Rx = lambda^2 - Ax - Bx
 
  223     // <=> lambda^2 = Rx + Ax + Bx
 
  228           *result.X + *A.X + *B.X,
 
  229           FMT(annotation_prefix, " Rx_constraint"))
 
  230     // Ry = lambda * (Ax - Rx) - Ay
 
  231     // <=> lambda * (Ax - Rx) = Ry + Ay
 
  237           FMT(annotation_prefix, " Ry_constraint"))
 
  241 template<typename wppT> void G2_add_gadget<wppT>::generate_r1cs_constraints()
 
  243     lambda_constraint.generate_r1cs_constraints();
 
  244     Rx_constraint.generate_r1cs_constraints();
 
  245     Ry_constraint.generate_r1cs_constraints();
 
  248 template<typename wppT> void G2_add_gadget<wppT>::generate_r1cs_witness()
 
  250     using nppT = other_curve<wppT>;
 
  251     const libff::Fqe<nppT> Ax = A.X->get_element();
 
  252     const libff::Fqe<nppT> Ay = A.Y->get_element();
 
  253     const libff::Fqe<nppT> Bx = B.X->get_element();
 
  254     const libff::Fqe<nppT> By = B.Y->get_element();
 
  256     // Guard against the inverse operation failing.
 
  258         throw std::runtime_error(
 
  259             "A.X == B.X is not supported by G2_add_gadget");
 
  262     // lambda = (By - Ay) / (Bx - Ax)
 
  263     const libff::Fqe<nppT> lambda_value = (By - Ay) * (Bx - Ax).inverse();
 
  264     lambda.generate_r1cs_witness(lambda_value);
 
  265     lambda_constraint.B.evaluate();
 
  266     lambda_constraint.result.evaluate();
 
  267     lambda_constraint.generate_r1cs_witness();
 
  269     // Rx = lambda^2 - Ax - Bx
 
  270     // Ry = lambda * (Ax - Rx) - Ay
 
  271     const libff::Fqe<nppT> Rx = lambda_value.squared() - Ax - Bx;
 
  272     const libff::Fqe<nppT> Ry = lambda_value * (Ax - Rx) - Ay;
 
  273     result.generate_r1cs_witness(
 
  274         libff::G2<nppT>(Rx, Ry, libff::Fqe<nppT>::one()));
 
  276     // lambda^2 = Rx + Ax + Bx
 
  277     Rx_constraint.result.evaluate();
 
  278     Rx_constraint.generate_r1cs_witness();
 
  280     // lambda * (Ax - Rx) = Ry + Ay
 
  281     Ry_constraint.B.evaluate();
 
  282     Ry_constraint.result.evaluate();
 
  283     Ry_constraint.generate_r1cs_witness();
 
  286 template<typename wppT>
 
  287 G2_dbl_gadget<wppT>::G2_dbl_gadget(
 
  288     protoboard<libff::Fr<wppT>> &pb,
 
  289     const G2_variable<wppT> &A,
 
  290     const G2_variable<wppT> &result,
 
  291     const std::string &annotation_prefix)
 
  292     : gadget<libff::Fr<wppT>>(pb, annotation_prefix)
 
  295     , lambda(pb, FMT(annotation_prefix, " lambda"))
 
  296     // Ax_squared = Ax * Ax
 
  297     , Ax_squared_constraint(
 
  301           Fqe_variable<wppT>(pb, FMT(annotation_prefix, " Ax^2")),
 
  302           FMT(annotation_prefix, " _Ax_squared_constraint"))
 
  303     // lambda = (3 * Ax^2 + a) / 2 * Ay
 
  304     // <=> lambda * (Ay + Ay) = 3 * Ax_squared + a
 
  309           Ax_squared_constraint.result * libff::Fr<wppT>(3) +
 
  310               libff::G2<nppT>::coeff_a,
 
  311           FMT(annotation_prefix, " lambda_constraint"))
 
  312     // Bx = lambda^2 - 2 * Ax
 
  313     // <=> lambda * lambda = Bx + Ax + Ax
 
  318           *result.X + *A.X + *A.X,
 
  319           FMT(annotation_prefix, " Bx_constraint"))
 
  320     // By = lambda * (Ax - Bx) - Ay
 
  321     // <=> lambda * (Ax - Bx) = By + Ay
 
  327           FMT(annotation_prefix, " By_constraint"))
 
  331 template<typename wppT> void G2_dbl_gadget<wppT>::generate_r1cs_constraints()
 
  333     Ax_squared_constraint.generate_r1cs_constraints();
 
  334     lambda_constraint.generate_r1cs_constraints();
 
  335     Bx_constraint.generate_r1cs_constraints();
 
  336     By_constraint.generate_r1cs_constraints();
 
  339 template<typename wppT> void G2_dbl_gadget<wppT>::generate_r1cs_witness()
 
  341     const libff::Fqe<nppT> Ax = A.X->get_element();
 
  342     const libff::Fqe<nppT> Ay = A.Y->get_element();
 
  344     // Ax_squared = Ax * Ax
 
  345     Ax_squared_constraint.generate_r1cs_witness();
 
  346     Ax_squared_constraint.result.evaluate();
 
  347     const libff::Fqe<nppT> Ax_squared =
 
  348         Ax_squared_constraint.result.get_element();
 
  350     // lambda = (3 * Ax^2 + a) / 2 * Ay
 
  351     // <=> lambda * (Ay + Ay) = 3 * Ax_squared + a
 
  352     const libff::Fqe<nppT> Ax_squared_plus_a =
 
  353         Ax_squared + Ax_squared + Ax_squared + libff::G2<nppT>::coeff_a;
 
  354     const libff::Fqe<nppT> lambda_value =
 
  355         Ax_squared_plus_a * (Ay + Ay).inverse();
 
  356     lambda.generate_r1cs_witness(lambda_value);
 
  357     lambda_constraint.B.evaluate();
 
  358     lambda_constraint.generate_r1cs_witness();
 
  360     // Bx = lambda^2 - 2 * Ax
 
  361     // By = lambda * (Ax - Bx) - Ay
 
  362     const libff::Fqe<nppT> Bx = lambda_value.squared() - Ax - Ax;
 
  363     const libff::Fqe<nppT> By = lambda_value * (Ax - Bx) - Ay;
 
  364     result.generate_r1cs_witness(
 
  365         libff::G2<nppT>(Bx, By, libff::Fqe<nppT>::one()));
 
  367     // lambda * lambda = Bx + Ax + Ax
 
  368     Bx_constraint.generate_r1cs_witness();
 
  370     // lambda * (Ax - Bx) = By + Ay
 
  371     By_constraint.B.evaluate();
 
  372     By_constraint.generate_r1cs_witness();
 
  375 template<typename wppT>
 
  376 G2_equality_gadget<wppT>::G2_equality_gadget(
 
  377     protoboard<libff::Fr<wppT>> &pb,
 
  378     const G2_variable<wppT> &A,
 
  379     const G2_variable<wppT> &B,
 
  380     const std::string &annotation_prefix)
 
  381     : gadget<libff::Fr<wppT>>(pb, annotation_prefix), _A(A), _B(B)
 
  385 template<typename wppT>
 
  386 void G2_equality_gadget<wppT>::generate_r1cs_constraints()
 
  389     generate_fpe_equality_constraints(*_A.X, *_B.X);
 
  391     generate_fpe_equality_constraints(*_A.X, *_B.X);
 
  394 template<typename wppT> void G2_equality_gadget<wppT>::generate_r1cs_witness()
 
  399 template<typename wppT>
 
  400 void G2_equality_gadget<wppT>::generate_fpe_equality_constraints(
 
  401     const Fp2_variable<libff::Fqe<other_curve<wppT>>> &a,
 
  402     const Fp2_variable<libff::Fqe<other_curve<wppT>>> &b)
 
  404     this->pb.add_r1cs_constraint(
 
  405         r1cs_constraint<libff::Fr<wppT>>(a.c0, 1, b.c0),
 
  406         FMT(this->annotation_prefix, " c0"));
 
  407     this->pb.add_r1cs_constraint(
 
  408         r1cs_constraint<libff::Fr<wppT>>(a.c1, 1, b.c1),
 
  409         FMT(this->annotation_prefix, " c1"));
 
  412 } // namespace libsnark
 
  414 #endif // WEIERSTRASS_G2_GADGET_TCC_