2  *****************************************************************************
 
    4  Implementation of interfaces for the Merkle tree check update gadget.
 
    6  See merkle_tree_check_update_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 MERKLE_TREE_CHECK_UPDATE_GADGET_TCC_
 
   15 #define MERKLE_TREE_CHECK_UPDATE_GADGET_TCC_
 
   20 template<typename FieldT, typename HashT>
 
   21 merkle_tree_check_update_gadget<FieldT, HashT>::merkle_tree_check_update_gadget(
 
   22     protoboard<FieldT> &pb,
 
   23     const size_t tree_depth,
 
   24     const pb_variable_array<FieldT> &address_bits,
 
   25     const digest_variable<FieldT> &prev_leaf_digest,
 
   26     const digest_variable<FieldT> &prev_root_digest,
 
   27     const merkle_authentication_path_variable<FieldT, HashT> &prev_path,
 
   28     const digest_variable<FieldT> &next_leaf_digest,
 
   29     const digest_variable<FieldT> &next_root_digest,
 
   30     const merkle_authentication_path_variable<FieldT, HashT> &next_path,
 
   31     const pb_linear_combination<FieldT> &update_successful,
 
   32     const std::string &annotation_prefix)
 
   33     : gadget<FieldT>(pb, annotation_prefix)
 
   34     , digest_size(HashT::get_digest_len())
 
   35     , tree_depth(tree_depth)
 
   36     , address_bits(address_bits)
 
   37     , prev_leaf_digest(prev_leaf_digest)
 
   38     , prev_root_digest(prev_root_digest)
 
   39     , prev_path(prev_path)
 
   40     , next_leaf_digest(next_leaf_digest)
 
   41     , next_root_digest(next_root_digest)
 
   42     , next_path(next_path)
 
   43     , update_successful(update_successful)
 
   45     assert(tree_depth > 0);
 
   46     assert(tree_depth == address_bits.size());
 
   48     for (size_t i = 0; i < tree_depth - 1; ++i) {
 
   49         prev_internal_output.emplace_back(digest_variable<FieldT>(
 
   52             FMT(this->annotation_prefix, " prev_internal_output_%zu", i)));
 
   53         next_internal_output.emplace_back(digest_variable<FieldT>(
 
   56             FMT(this->annotation_prefix, " next_internal_output_%zu", i)));
 
   59     computed_next_root.reset(new digest_variable<FieldT>(
 
   60         pb, digest_size, FMT(this->annotation_prefix, " computed_root")));
 
   62     for (size_t i = 0; i < tree_depth; ++i) {
 
   63         block_variable<FieldT> prev_inp(
 
   65             prev_path.left_digests[i],
 
   66             prev_path.right_digests[i],
 
   67             FMT(this->annotation_prefix, " prev_inp_%zu", i));
 
   68         prev_hasher_inputs.emplace_back(prev_inp);
 
   69         prev_hashers.emplace_back(HashT(
 
   73             (i == 0 ? prev_root_digest : prev_internal_output[i - 1]),
 
   74             FMT(this->annotation_prefix, " prev_hashers_%zu", i)));
 
   76         block_variable<FieldT> next_inp(
 
   78             next_path.left_digests[i],
 
   79             next_path.right_digests[i],
 
   80             FMT(this->annotation_prefix, " next_inp_%zu", i));
 
   81         next_hasher_inputs.emplace_back(next_inp);
 
   82         next_hashers.emplace_back(HashT(
 
   86             (i == 0 ? *computed_next_root : next_internal_output[i - 1]),
 
   87             FMT(this->annotation_prefix, " next_hashers_%zu", i)));
 
   90     for (size_t i = 0; i < tree_depth; ++i) {
 
   91         prev_propagators.emplace_back(digest_selector_gadget<FieldT>(
 
   94             i < tree_depth - 1 ? prev_internal_output[i] : prev_leaf_digest,
 
   95             address_bits[tree_depth - 1 - i],
 
   96             prev_path.left_digests[i],
 
   97             prev_path.right_digests[i],
 
   98             FMT(this->annotation_prefix, " prev_propagators_%zu", i)));
 
   99         next_propagators.emplace_back(digest_selector_gadget<FieldT>(
 
  102             i < tree_depth - 1 ? next_internal_output[i] : next_leaf_digest,
 
  103             address_bits[tree_depth - 1 - i],
 
  104             next_path.left_digests[i],
 
  105             next_path.right_digests[i],
 
  106             FMT(this->annotation_prefix, " next_propagators_%zu", i)));
 
  109     check_next_root.reset(new bit_vector_copy_gadget<FieldT>(
 
  111         computed_next_root->bits,
 
  112         next_root_digest.bits,
 
  115         FMT(annotation_prefix, " check_next_root")));
 
  118 template<typename FieldT, typename HashT>
 
  119 void merkle_tree_check_update_gadget<FieldT, HashT>::generate_r1cs_constraints()
 
  121     // ensure correct hash computations
 
  122     for (size_t i = 0; i < tree_depth; ++i) {
 
  123         // we check root outside and prev_left/prev_right above
 
  124         prev_hashers[i].generate_r1cs_constraints(false);
 
  125         // however we must check right side hashes
 
  126         next_hashers[i].generate_r1cs_constraints(true);
 
  129     // ensure consistency of internal_left/internal_right with internal_output
 
  130     for (size_t i = 0; i < tree_depth; ++i) {
 
  131         prev_propagators[i].generate_r1cs_constraints();
 
  132         next_propagators[i].generate_r1cs_constraints();
 
  135     /* ensure that prev auxiliary input and next auxiliary input match */
 
  136     for (size_t i = 0; i < tree_depth; ++i) {
 
  137         for (size_t j = 0; j < digest_size; ++j) {
 
  139               addr * (prev_left - next_left) + (1 - addr) * (prev_right -
 
  140               next_right) = 0 addr * (prev_left - next_left - prev_right +
 
  141               next_right) = next_right - prev_right
 
  143             this->pb.add_r1cs_constraint(
 
  144                 r1cs_constraint<FieldT>(
 
  145                     address_bits[tree_depth - 1 - i],
 
  146                     prev_path.left_digests[i].bits[j] -
 
  147                         next_path.left_digests[i].bits[j] -
 
  148                         prev_path.right_digests[i].bits[j] +
 
  149                         next_path.right_digests[i].bits[j],
 
  150                     next_path.right_digests[i].bits[j] -
 
  151                         prev_path.right_digests[i].bits[j]),
 
  152                 FMT(this->annotation_prefix, " aux_check_%zu_%zu", i, j));
 
  156     /* Note that while it is necessary to generate R1CS constraints
 
  157        for prev_path, it is not necessary to do so for next_path.
 
  159        This holds, because { next_path.left_inputs[i],
 
  160        next_path.right_inputs[i] } is a pair { hash_output,
 
  161        auxiliary_input }. The bitness for hash_output is enforced
 
  162        above by next_hashers[i].generate_r1cs_constraints.
 
  164        Because auxiliary input is the same for prev_path and next_path
 
  165        (enforced above), we have that auxiliary_input part is also
 
  166        constrained to be boolean, because prev_path is *all*
 
  167        constrained to be all boolean. */
 
  169     check_next_root->generate_r1cs_constraints(false, false);
 
  172 template<typename FieldT, typename HashT>
 
  173 void merkle_tree_check_update_gadget<FieldT, HashT>::generate_r1cs_witness()
 
  175     /* do the hash computations bottom-up */
 
  176     for (int i = tree_depth - 1; i >= 0; --i) {
 
  177         /* ensure consistency of prev_path and next_path */
 
  178         if (this->pb.val(address_bits[tree_depth - 1 - i]) == FieldT::one()) {
 
  179             next_path.left_digests[i].generate_r1cs_witness(
 
  180                 prev_path.left_digests[i].get_digest());
 
  182             next_path.right_digests[i].generate_r1cs_witness(
 
  183                 prev_path.right_digests[i].get_digest());
 
  186         /* propagate previous input */
 
  187         prev_propagators[i].generate_r1cs_witness();
 
  188         next_propagators[i].generate_r1cs_witness();
 
  191         prev_hashers[i].generate_r1cs_witness();
 
  192         next_hashers[i].generate_r1cs_witness();
 
  195     check_next_root->generate_r1cs_witness();
 
  198 template<typename FieldT, typename HashT>
 
  199 size_t merkle_tree_check_update_gadget<FieldT, HashT>::root_size_in_bits()
 
  201     return HashT::get_digest_len();
 
  204 template<typename FieldT, typename HashT>
 
  205 size_t merkle_tree_check_update_gadget<FieldT, HashT>::expected_constraints(
 
  206     const size_t tree_depth)
 
  208     /* NB: this includes path constraints */
 
  209     const size_t prev_hasher_constraints =
 
  210         tree_depth * HashT::expected_constraints(false);
 
  211     const size_t next_hasher_constraints =
 
  212         tree_depth * HashT::expected_constraints(true);
 
  213     const size_t prev_authentication_path_constraints =
 
  214         2 * tree_depth * HashT::get_digest_len();
 
  215     const size_t prev_propagator_constraints =
 
  216         tree_depth * HashT::get_digest_len();
 
  217     const size_t next_propagator_constraints =
 
  218         tree_depth * HashT::get_digest_len();
 
  219     const size_t check_next_root_constraints =
 
  220         3 * libff::div_ceil(HashT::get_digest_len(), FieldT::capacity());
 
  221     const size_t aux_equality_constraints =
 
  222         tree_depth * HashT::get_digest_len();
 
  225         prev_hasher_constraints + next_hasher_constraints +
 
  226         prev_authentication_path_constraints + prev_propagator_constraints +
 
  227         next_propagator_constraints + check_next_root_constraints +
 
  228         aux_equality_constraints);
 
  231 template<typename FieldT, typename HashT>
 
  232 void test_merkle_tree_check_update_gadget()
 
  235     const size_t digest_len = HashT::get_digest_len();
 
  237     const size_t tree_depth = 16;
 
  238     std::vector<merkle_authentication_node> prev_path(tree_depth);
 
  240     libff::bit_vector prev_load_hash(digest_len);
 
  241     std::generate(prev_load_hash.begin(), prev_load_hash.end(), [&]() {
 
  242         return std::rand() % 2;
 
  244     libff::bit_vector prev_store_hash(digest_len);
 
  245     std::generate(prev_store_hash.begin(), prev_store_hash.end(), [&]() {
 
  246         return std::rand() % 2;
 
  249     libff::bit_vector loaded_leaf = prev_load_hash;
 
  250     libff::bit_vector stored_leaf = prev_store_hash;
 
  252     libff::bit_vector address_bits;
 
  255     for (long level = tree_depth - 1; level >= 0; --level) {
 
  256         const bool computed_is_right = (std::rand() % 2);
 
  257         address |= (computed_is_right ? 1ul << (tree_depth - 1 - level) : 0);
 
  258         address_bits.push_back(computed_is_right);
 
  259         libff::bit_vector other(digest_len);
 
  261             other.begin(), other.end(), [&]() { return std::rand() % 2; });
 
  263         libff::bit_vector load_block = prev_load_hash;
 
  265             computed_is_right ? load_block.begin() : load_block.end(),
 
  268         libff::bit_vector store_block = prev_store_hash;
 
  270             computed_is_right ? store_block.begin() : store_block.end(),
 
  274         libff::bit_vector load_h = HashT::get_hash(load_block);
 
  275         libff::bit_vector store_h = HashT::get_hash(store_block);
 
  277         prev_path[level] = other;
 
  279         prev_load_hash = load_h;
 
  280         prev_store_hash = store_h;
 
  283     libff::bit_vector load_root = prev_load_hash;
 
  284     libff::bit_vector store_root = prev_store_hash;
 
  286     /* execute the test */
 
  287     protoboard<FieldT> pb;
 
  288     pb_variable_array<FieldT> address_bits_va;
 
  289     address_bits_va.allocate(pb, tree_depth, "address_bits");
 
  290     digest_variable<FieldT> prev_leaf_digest(
 
  291         pb, digest_len, "prev_leaf_digest");
 
  292     digest_variable<FieldT> prev_root_digest(
 
  293         pb, digest_len, "prev_root_digest");
 
  294     merkle_authentication_path_variable<FieldT, HashT> prev_path_var(
 
  295         pb, tree_depth, "prev_path_var");
 
  296     digest_variable<FieldT> next_leaf_digest(
 
  297         pb, digest_len, "next_leaf_digest");
 
  298     digest_variable<FieldT> next_root_digest(
 
  299         pb, digest_len, "next_root_digest");
 
  300     merkle_authentication_path_variable<FieldT, HashT> next_path_var(
 
  301         pb, tree_depth, "next_path_var");
 
  302     merkle_tree_check_update_gadget<FieldT, HashT> mls(
 
  315     prev_path_var.generate_r1cs_constraints();
 
  316     mls.generate_r1cs_constraints();
 
  318     address_bits_va.fill_with_bits(pb, address_bits);
 
  320         address_bits_va.get_field_element_from_bits(pb).as_ulong() == address);
 
  321     prev_leaf_digest.generate_r1cs_witness(loaded_leaf);
 
  322     prev_path_var.generate_r1cs_witness(address, prev_path);
 
  323     next_leaf_digest.generate_r1cs_witness(stored_leaf);
 
  324     address_bits_va.fill_with_bits(pb, address_bits);
 
  325     mls.generate_r1cs_witness();
 
  327     /* make sure that update check will check for the right things */
 
  328     prev_leaf_digest.generate_r1cs_witness(loaded_leaf);
 
  329     next_leaf_digest.generate_r1cs_witness(stored_leaf);
 
  330     prev_root_digest.generate_r1cs_witness(load_root);
 
  331     next_root_digest.generate_r1cs_witness(store_root);
 
  332     address_bits_va.fill_with_bits(pb, address_bits);
 
  333     assert(pb.is_satisfied());
 
  336     const size_t num_constraints = pb.num_constraints();
 
  337     const size_t expected_constraints =
 
  338         merkle_tree_check_update_gadget<FieldT, HashT>::expected_constraints(
 
  341     assert(num_constraints == expected_constraints);
 
  344 } // namespace libsnark
 
  346 #endif // MERKLE_TREE_CHECK_UPDATE_GADGET_TCC_