2  *****************************************************************************
 
    4  Implementation of interfaces for the exponentiation gadget.
 
    6  See exponentiation_gadget.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 EXPONENTIATION_GADGET_TCC_
 
   15 #define EXPONENTIATION_GADGET_TCC_
 
   25     class Fpk_mul_gadgetT,
 
   27     class Fpk_sqr_gadgetT,
 
   29 exponentiation_gadget<
 
   35     exponentiation_gadget(
 
   36         protoboard<FieldT> &pb,
 
   37         const Fpk_variableT<FpkT> &elt,
 
   38         const libff::bigint<m> &power,
 
   39         const Fpk_variableT<FpkT> &result,
 
   40         const std::string &annotation_prefix)
 
   41     : gadget<FieldT>(pb, annotation_prefix)
 
   46     NAF = find_wnaf(1, power);
 
   53     bool found_nonzero = false;
 
   54     for (long i = NAF.size() - 1; i >= 0; --i) {
 
   73     intermediate.resize(intermed_count);
 
   74     intermediate[0].reset(new Fpk_variableT<FpkT>(
 
   75         pb, FpkT::one(), FMT(annotation_prefix, " intermediate_0")));
 
   76     for (size_t i = 1; i < intermed_count; ++i) {
 
   77         intermediate[i].reset(new Fpk_variableT<FpkT>(
 
   78             pb, FMT(annotation_prefix, " intermediate_%zu", i)));
 
   80     addition_steps.resize(add_count);
 
   81     subtraction_steps.resize(sub_count);
 
   82     doubling_steps.resize(dbl_count);
 
   84     found_nonzero = false;
 
   86     size_t dbl_id = 0, add_id = 0, sub_id = 0, intermed_id = 0;
 
   88     for (long i = NAF.size() - 1; i >= 0; --i) {
 
   90             doubling_steps[dbl_id].reset(new Fpk_sqr_gadgetT<FpkT>(
 
   92                 *intermediate[intermed_id],
 
   93                 (intermed_id + 1 == intermed_count
 
   95                      : *intermediate[intermed_id + 1]),
 
   96                 FMT(annotation_prefix, " doubling_steps_%zu", dbl_count)));
 
  102             found_nonzero = true;
 
  105                 /* next = cur * elt */
 
  106                 addition_steps[add_id].reset(new Fpk_mul_gadgetT<FpkT>(
 
  108                     *intermediate[intermed_id],
 
  110                     (intermed_id + 1 == intermed_count
 
  112                          : *intermediate[intermed_id + 1]),
 
  113                     FMT(annotation_prefix, " addition_steps_%zu", dbl_count)));
 
  117                 /* next = cur / elt, i.e. next * elt = cur */
 
  118                 subtraction_steps[sub_id].reset(new Fpk_mul_gadgetT<FpkT>(
 
  120                     (intermed_id + 1 == intermed_count
 
  122                          : *intermediate[intermed_id + 1]),
 
  124                     *intermediate[intermed_id],
 
  125                     FMT(annotation_prefix,
 
  126                         " subtraction_steps_%zu",
 
  140     class Fpk_mul_gadgetT,
 
  142     class Fpk_sqr_gadgetT,
 
  144 void exponentiation_gadget<
 
  149     m>::generate_r1cs_constraints()
 
  151     for (size_t i = 0; i < add_count; ++i) {
 
  152         addition_steps[i]->generate_r1cs_constraints();
 
  155     for (size_t i = 0; i < sub_count; ++i) {
 
  156         subtraction_steps[i]->generate_r1cs_constraints();
 
  159     for (size_t i = 0; i < dbl_count; ++i) {
 
  160         doubling_steps[i]->generate_r1cs_constraints();
 
  169     class Fpk_mul_gadgetT,
 
  171     class Fpk_sqr_gadgetT,
 
  173 void exponentiation_gadget<
 
  178     m>::generate_r1cs_witness()
 
  180     intermediate[0]->generate_r1cs_witness(FpkT::one());
 
  182     bool found_nonzero = false;
 
  183     size_t dbl_id = 0, add_id = 0, sub_id = 0, intermed_id = 0;
 
  185     for (long i = NAF.size() - 1; i >= 0; --i) {
 
  187             doubling_steps[dbl_id]->generate_r1cs_witness();
 
  193             found_nonzero = true;
 
  196                 addition_steps[add_id]->generate_r1cs_witness();
 
  200                 const FpkT cur_val = intermediate[intermed_id]->get_element();
 
  201                 const FpkT elt_val = elt.get_element();
 
  202                 const FpkT next_val = cur_val * elt_val.inverse();
 
  204                 (intermed_id + 1 == intermed_count
 
  206                      : *intermediate[intermed_id + 1])
 
  207                     .generate_r1cs_witness(next_val);
 
  209                 subtraction_steps[sub_id]->generate_r1cs_witness();
 
  223     class Fpk_mul_gadgetT,
 
  225     class Fpk_sqr_gadgetT,
 
  227 void test_exponentiation_gadget(
 
  228     const libff::bigint<m> &power, const std::string &annotation)
 
  230     typedef typename FpkT::my_Fp FieldT;
 
  232     protoboard<FieldT> pb;
 
  233     Fpk_variableT<FpkT> x(pb, "x");
 
  234     Fpk_variableT<FpkT> x_to_power(pb, "x_to_power");
 
  235     exponentiation_gadget<
 
  241         exp_gadget(pb, x, power, x_to_power, "exp_gadget");
 
  242     exp_gadget.generate_r1cs_constraints();
 
  244     for (size_t i = 0; i < 10; ++i) {
 
  245         const FpkT x_val = FpkT::random_element();
 
  246         x.generate_r1cs_witness(x_val);
 
  247         exp_gadget.generate_r1cs_witness();
 
  248         assert(pb.is_satisfied());
 
  249         assert(x_to_power.get_element() == (x_val ^ power));
 
  252         "number of constraints for %s_exp = %zu\n",
 
  254         pb.num_constraints());
 
  255     printf("exponent was: ");
 
  259 } // namespace libsnark
 
  261 #endif // EXPONENTIATION_GADGET_TCC_