Zeth - Zerocash on Ethereum  0.8
Reference implementation of the Zeth protocol by Clearmatics
merkle_path_compute.tcc
Go to the documentation of this file.
1 // DISCLAIMER:
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
5 
6 #ifndef __ZETH_CIRCUITS_MERKLE_PATH_COMPUTE_TCC__
7 #define __ZETH_CIRCUITS_MERKLE_PATH_COMPUTE_TCC__
8 
9 namespace libzeth
10 {
11 
12 template<typename FieldT, typename HashTreeT>
13 merkle_path_compute<FieldT, HashTreeT>::merkle_path_compute(
14  libsnark::protoboard<FieldT> &pb,
15  const size_t depth,
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)
21  , depth(depth)
22  , address_bits(address_bits)
23  , leaf(leaf)
24  , path(path)
25 {
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
28  assert(depth > 0);
29  assert(address_bits.size() == depth);
30 
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++) {
34 
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
39  if (i == 0) {
40  selectors.push_back(merkle_path_selector<FieldT>(
41  pb,
42  leaf,
43  path[i],
44  address_bits[i],
45  FMT(this->annotation_prefix, " selector[%zu]", i)));
46  } else {
47  selectors.push_back(merkle_path_selector<FieldT>(
48  pb,
49  digests[i - 1],
50  path[i],
51  address_bits[i],
52  FMT(this->annotation_prefix, " selector[%zu]", i)));
53  }
54 
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(
58  pb,
59  {selectors[i].get_left()},
60  selectors[i].get_right(),
61  digests[i],
62  FMT(this->annotation_prefix, " hasher[%zu]", i));
63 
64  // We append the initialized hasher in the vector of hashers
65  hashers.push_back(t);
66  }
67 };
68 
69 template<typename FieldT, typename HashTreeT>
70 void merkle_path_compute<FieldT, HashTreeT>::generate_r1cs_constraints()
71 {
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();
77  }
78 };
79 
80 template<typename FieldT, typename HashTreeT>
81 void merkle_path_compute<FieldT, HashTreeT>::generate_r1cs_witness()
82 {
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();
89  }
90 };
91 
92 template<typename FieldT, typename HashTreeT>
93 const libsnark::pb_variable<FieldT> merkle_path_compute<FieldT, HashTreeT>::
94  result()
95 {
96  // We first check that we are not working with an empty tree
97  assert(digests.size() > 0);
98 
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];
102 };
103 
104 } // namespace libzeth
105 
106 #endif // __ZETH_CIRCUITS_MERKLE_PATH_COMPUTE_TCC__