2 // Content taken and adapted from:
3 // https://github.com/HarryR/ethsnarks/blob/master/src/gadgets/merkle_tree.hpp
4 // https://github.com/HarryR/ethsnarks/blob/master/src/gadgets/merkle_tree.cpp
6 #ifndef __ZETH_CIRCUITS_MERKLE_PATH_COMPUTE_TCC__
7 #define __ZETH_CIRCUITS_MERKLE_PATH_COMPUTE_TCC__
12 template<typename FieldT, typename HashTreeT>
13 merkle_path_compute<FieldT, HashTreeT>::merkle_path_compute(
14 libsnark::protoboard<FieldT> &pb,
16 const libsnark::pb_variable_array<FieldT> &address_bits,
17 const libsnark::pb_variable<FieldT> leaf,
18 const libsnark::pb_variable_array<FieldT> &path,
19 const std::string &annotation_prefix)
20 : libsnark::gadget<FieldT>(pb, annotation_prefix)
22 , address_bits(address_bits)
26 // We first assert that we are not working with an empty tree
27 // and that the leaf path is consistent with the tree size
29 assert(address_bits.size() == depth);
31 // For each layer of the tree
32 digests.allocate(pb, depth, FMT(annotation_prefix, " digests"));
33 for (size_t i = 0; i < depth; i++) {
35 // We first initialize the gadget to order the computed hash and the
36 // authentication node to know which one is the first to be hashed and
37 // which one is the second (as in mimc_hash(left, right)) We also append
38 // the initialized gadget in the vector of selectors
40 selectors.push_back(merkle_path_selector<FieldT>(
45 FMT(this->annotation_prefix, " selector[%zu]", i)));
47 selectors.push_back(merkle_path_selector<FieldT>(
52 FMT(this->annotation_prefix, " selector[%zu]", i)));
55 // We initialize the gadget to compute the next level hash input
56 // with the level's authentication node and the previously computed hash
57 HashTreeT t = HashTreeT(
59 {selectors[i].get_left()},
60 selectors[i].get_right(),
62 FMT(this->annotation_prefix, " hasher[%zu]", i));
64 // We append the initialized hasher in the vector of hashers
69 template<typename FieldT, typename HashTreeT>
70 void merkle_path_compute<FieldT, HashTreeT>::generate_r1cs_constraints()
72 // For each level of the tree
73 for (size_t i = 0; i < hashers.size(); i++) {
74 // We constraint the selector and hash gadgets
75 selectors[i].generate_r1cs_constraints();
76 hashers[i].generate_r1cs_constraints();
80 template<typename FieldT, typename HashTreeT>
81 void merkle_path_compute<FieldT, HashTreeT>::generate_r1cs_witness()
83 // For each level of the tree
84 for (size_t i = 0; i < hashers.size(); i++) {
85 // We compute the left and right input of the hasher gadget
86 // as well as the hash of left and right
87 selectors[i].generate_r1cs_witness();
88 hashers[i].generate_r1cs_witness();
92 template<typename FieldT, typename HashTreeT>
93 const libsnark::pb_variable<FieldT> merkle_path_compute<FieldT, HashTreeT>::
96 // We first check that we are not working with an empty tree
97 assert(digests.size() > 0);
99 // We return the last hasher result, that is to say the computed root,
100 // generated out of leaf, leaf address and merkle authentication path
101 return digests[digests.size() - 1];
104 } // namespace libzeth
106 #endif // __ZETH_CIRCUITS_MERKLE_PATH_COMPUTE_TCC__