2  *****************************************************************************
 
    4  Implementation of interfaces for the knapsack gadget.
 
    6  See knapsack_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 KNAPSACK_GADGET_TCC_
 
   15 #define KNAPSACK_GADGET_TCC_
 
   17 #include <libff/algebra/fields/field_utils.hpp>
 
   18 #include <libff/common/rng.hpp>
 
   23 template<typename FieldT>
 
   25     knapsack_CRH_with_field_out_gadget<FieldT>::knapsack_coefficients;
 
   26 template<typename FieldT>
 
   27 size_t knapsack_CRH_with_field_out_gadget<FieldT>::num_cached_coefficients;
 
   29 template<typename FieldT>
 
   30 knapsack_CRH_with_field_out_gadget<FieldT>::knapsack_CRH_with_field_out_gadget(
 
   31     protoboard<FieldT> &pb,
 
   32     const size_t input_len,
 
   33     const block_variable<FieldT> &input_block,
 
   34     const pb_linear_combination_array<FieldT> &output,
 
   35     const std::string &annotation_prefix)
 
   36     : gadget<FieldT>(pb, annotation_prefix)
 
   37     , input_len(input_len)
 
   38     , dimension(knapsack_dimension<FieldT>::dimension)
 
   39     , input_block(input_block)
 
   42     assert(input_block.bits.size() == input_len);
 
   43     if (num_cached_coefficients < dimension * input_len) {
 
   44         sample_randomness(input_len);
 
   46     assert(output.size() == this->get_digest_len());
 
   49 template<typename FieldT>
 
   50 void knapsack_CRH_with_field_out_gadget<FieldT>::generate_r1cs_constraints()
 
   52     for (size_t i = 0; i < dimension; ++i) {
 
   53         this->pb.add_r1cs_constraint(
 
   54             r1cs_constraint<FieldT>(
 
   59                         knapsack_coefficients.begin() + input_len * i,
 
   60                         knapsack_coefficients.begin() + input_len * (i + 1))),
 
   62             FMT(this->annotation_prefix, " knapsack_%zu", i));
 
   66 template<typename FieldT>
 
   67 void knapsack_CRH_with_field_out_gadget<FieldT>::generate_r1cs_witness()
 
   69     const libff::bit_vector input = input_block.get_block();
 
   71     for (size_t i = 0; i < dimension; ++i) {
 
   72         FieldT sum = FieldT::zero();
 
   73         for (size_t k = 0; k < input_len; ++k) {
 
   75                 sum += knapsack_coefficients[input_len * i + k];
 
   79         this->pb.lc_val(output[i]) = sum;
 
   83 template<typename FieldT>
 
   84 size_t knapsack_CRH_with_field_out_gadget<FieldT>::get_digest_len()
 
   86     return knapsack_dimension<FieldT>::dimension;
 
   89 template<typename FieldT>
 
   90 size_t knapsack_CRH_with_field_out_gadget<FieldT>::get_block_len()
 
   95 template<typename FieldT>
 
   96 std::vector<FieldT> knapsack_CRH_with_field_out_gadget<FieldT>::get_hash(
 
   97     const libff::bit_vector &input)
 
   99     const size_t dimension = knapsack_dimension<FieldT>::dimension;
 
  100     if (num_cached_coefficients < dimension * input.size()) {
 
  101         sample_randomness(input.size());
 
  104     std::vector<FieldT> result(dimension, FieldT::zero());
 
  106     for (size_t i = 0; i < dimension; ++i) {
 
  107         for (size_t k = 0; k < input.size(); ++k) {
 
  109                 result[i] += knapsack_coefficients[input.size() * i + k];
 
  117 template<typename FieldT>
 
  118 size_t knapsack_CRH_with_field_out_gadget<FieldT>::expected_constraints()
 
  120     return knapsack_dimension<FieldT>::dimension;
 
  123 template<typename FieldT>
 
  124 void knapsack_CRH_with_field_out_gadget<FieldT>::sample_randomness(
 
  125     const size_t input_len)
 
  127     const size_t num_coefficients =
 
  128         knapsack_dimension<FieldT>::dimension * input_len;
 
  129     if (num_coefficients > num_cached_coefficients) {
 
  130         knapsack_coefficients.resize(num_coefficients);
 
  131         for (size_t i = num_cached_coefficients; i < num_coefficients; ++i) {
 
  132             knapsack_coefficients[i] = libff::SHA512_rng<FieldT>(i);
 
  134         num_cached_coefficients = num_coefficients;
 
  138 template<typename FieldT>
 
  139 knapsack_CRH_with_bit_out_gadget<FieldT>::knapsack_CRH_with_bit_out_gadget(
 
  140     protoboard<FieldT> &pb,
 
  141     const size_t input_len,
 
  142     const block_variable<FieldT> &input_block,
 
  143     const digest_variable<FieldT> &output_digest,
 
  144     const std::string &annotation_prefix)
 
  145     : gadget<FieldT>(pb, annotation_prefix)
 
  146     , input_len(input_len)
 
  147     , dimension(knapsack_dimension<FieldT>::dimension)
 
  148     , input_block(input_block)
 
  149     , output_digest(output_digest)
 
  151     assert(output_digest.bits.size() == this->get_digest_len());
 
  153     output.resize(dimension);
 
  155     for (size_t i = 0; i < dimension; ++i) {
 
  158             pb_packing_sum<FieldT>(pb_variable_array<FieldT>(
 
  159                 output_digest.bits.begin() + i * FieldT::size_in_bits(),
 
  160                 output_digest.bits.begin() +
 
  161                     (i + 1) * FieldT::size_in_bits())));
 
  164     hasher.reset(new knapsack_CRH_with_field_out_gadget<FieldT>(
 
  165         pb, input_len, input_block, output, FMT(annotation_prefix, " hasher")));
 
  168 template<typename FieldT>
 
  169 void knapsack_CRH_with_bit_out_gadget<FieldT>::generate_r1cs_constraints(
 
  170     const bool enforce_bitness)
 
  172     hasher->generate_r1cs_constraints();
 
  174     if (enforce_bitness) {
 
  175         for (size_t k = 0; k < output_digest.bits.size(); ++k) {
 
  176             generate_boolean_r1cs_constraint<FieldT>(
 
  178                 output_digest.bits[k],
 
  179                 FMT(this->annotation_prefix, " output_digest_%zu", k));
 
  184 template<typename FieldT>
 
  185 void knapsack_CRH_with_bit_out_gadget<FieldT>::generate_r1cs_witness()
 
  187     hasher->generate_r1cs_witness();
 
  189     /* do unpacking in place */
 
  190     const libff::bit_vector input = input_block.bits.get_bits(this->pb);
 
  191     for (size_t i = 0; i < dimension; ++i) {
 
  192         pb_variable_array<FieldT> va(
 
  193             output_digest.bits.begin() + i * FieldT::size_in_bits(),
 
  194             output_digest.bits.begin() + (i + 1) * FieldT::size_in_bits());
 
  195         va.fill_with_bits_of_field_element(
 
  196             this->pb, this->pb.lc_val(output[i]));
 
  200 template<typename FieldT>
 
  201 size_t knapsack_CRH_with_bit_out_gadget<FieldT>::get_digest_len()
 
  203     return knapsack_dimension<FieldT>::dimension * FieldT::size_in_bits();
 
  206 template<typename FieldT>
 
  207 size_t knapsack_CRH_with_bit_out_gadget<FieldT>::get_block_len()
 
  212 template<typename FieldT>
 
  213 libff::bit_vector knapsack_CRH_with_bit_out_gadget<FieldT>::get_hash(
 
  214     const libff::bit_vector &input)
 
  216     const std::vector<FieldT> hash_elems =
 
  217         knapsack_CRH_with_field_out_gadget<FieldT>::get_hash(input);
 
  218     hash_value_type result;
 
  220     for (const FieldT &elt : hash_elems) {
 
  221         libff::bit_vector elt_bits =
 
  222             libff::convert_field_element_to_bit_vector<FieldT>(elt);
 
  223         result.insert(result.end(), elt_bits.begin(), elt_bits.end());
 
  229 template<typename FieldT>
 
  230 size_t knapsack_CRH_with_bit_out_gadget<FieldT>::expected_constraints(
 
  231     const bool enforce_bitness)
 
  233     const size_t hasher_constraints =
 
  234         knapsack_CRH_with_field_out_gadget<FieldT>::expected_constraints();
 
  235     const size_t bitness_constraints = (enforce_bitness ? get_digest_len() : 0);
 
  236     return hasher_constraints + bitness_constraints;
 
  239 template<typename FieldT>
 
  240 void knapsack_CRH_with_bit_out_gadget<FieldT>::sample_randomness(
 
  241     const size_t input_len)
 
  243     knapsack_CRH_with_field_out_gadget<FieldT>::sample_randomness(input_len);
 
  246 template<typename FieldT>
 
  247 void test_knapsack_CRH_with_bit_out_gadget_internal(
 
  248     const size_t dimension,
 
  249     const libff::bit_vector &input_bits,
 
  250     const libff::bit_vector &digest_bits)
 
  252     assert(knapsack_dimension<FieldT>::dimension == dimension);
 
  253     knapsack_CRH_with_bit_out_gadget<FieldT>::sample_randomness(
 
  255     protoboard<FieldT> pb;
 
  257     block_variable<FieldT> input_block(pb, input_bits.size(), "input_block");
 
  258     digest_variable<FieldT> output_digest(
 
  260         knapsack_CRH_with_bit_out_gadget<FieldT>::get_digest_len(),
 
  262     knapsack_CRH_with_bit_out_gadget<FieldT> H(
 
  263         pb, input_bits.size(), input_block, output_digest, "H");
 
  265     input_block.generate_r1cs_witness(input_bits);
 
  266     H.generate_r1cs_constraints();
 
  267     H.generate_r1cs_witness();
 
  269     assert(output_digest.get_digest().size() == digest_bits.size());
 
  270     assert(pb.is_satisfied());
 
  272     const size_t num_constraints = pb.num_constraints();
 
  273     const size_t expected_constraints =
 
  274         knapsack_CRH_with_bit_out_gadget<FieldT>::expected_constraints();
 
  275     assert(num_constraints == expected_constraints);
 
  278     libff::UNUSED(dimension);
 
  279     libff::UNUSED(digest_bits);
 
  280     libff::UNUSED(num_constraints);
 
  281     libff::UNUSED(expected_constraints);
 
  285 } // namespace libsnark
 
  287 #endif // KNAPSACK_GADGET_TCC_