Longfellow ZK 0290cb32
Loading...
Searching...
No Matches
merkle_tree.h
1// Copyright 2025 Google LLC.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#ifndef PRIVACY_PROOFS_ZK_LIB_MERKLE_MERKLE_TREE_H_
16#define PRIVACY_PROOFS_ZK_LIB_MERKLE_MERKLE_TREE_H_
17
18#include <stddef.h>
19#include <stdint.h>
20
21#include <cstring>
22#include <vector>
23
24#include "util/crypto.h"
25#include "util/panic.h"
26
27namespace proofs {
28
29// This package computes and verifies Merkle Tree inclusion claims.
30// The standard Merkle tree algorithm has been implemented.
31
32// A digest of a Merkle tree.
33struct Digest {
34 static constexpr size_t kLength = kSHA256DigestSize;
35 uint8_t data[kLength];
36
37 bool operator==(const Digest& y) const {
38 return memcmp(data, y.data, kLength) == 0;
39 }
40
41 static Digest hash2(const Digest& L, const Digest& R) {
42 SHA256 sha;
43 sha.Update(L.data, kLength);
44 sha.Update(R.data, kLength);
45 Digest output;
46 sha.DigestData(output.data);
47 return output;
48 }
49};
50
51// Return the length of the proof for N leaves.
52// Mimic the code in generate_proof() without actually
53// computing the proof
54inline size_t merkle_tree_len(size_t n) {
55 size_t r = 1;
56 size_t pos = (n - 1); // maximum possible value
57 for (pos += n; pos > 1; pos >>= 1) {
58 ++r;
59 }
60 return r;
61}
62
63// compute the set of all nodes on the path from the
64// root to any leaf in POS.
65inline std::vector<bool> compressed_merkle_proof_tree(size_t n,
66 const size_t pos[/*np*/],
67 size_t np) {
68 check(np > 0, "A Merkle proof with 0 leaves is not defined.");
69 std::vector<bool> tree(2 * n, false);
70
71 // leaves are in TREE
72 for (size_t ip = 0; ip < np; ++ip) {
73 check(pos[ip] < n, "Invalid position for leaf in Merkle tree");
74 tree[pos[ip] + n] = true;
75 }
76
77 // If a child of an inner node is in TREE, then the parent is in TREE.
78 for (size_t i = n; i-- > 1;) {
79 tree[i] = (tree[2 * i] || tree[2 * i + 1]);
80 }
81
82 // Assert that the root is in TREE.
83 check(tree[1], "tree[1]");
84
85 return tree;
86}
87
88class MerkleTree {
89 public:
90 explicit MerkleTree(size_t n) : n_(n), layers_(2 * n) {}
91
92 void set_leaf(size_t pos, const Digest& leaf) {
93 check(pos < n_, "Invalid position for leaf in Merkle tree");
94 layers_[pos + n_] = leaf;
95 }
96
97 Digest build_tree() {
98 for (size_t i = n_; i-- > 1;) {
99 layers_[i] = Digest::hash2(layers_[2 * i], layers_[2 * i + 1]);
100 }
101 return layers_[1];
102 }
103
104 // The generate_proof method writes a Merkle tree proof for the leaf
105 // at position pos into the proof array and returns the size of the proof
106 // in number of Digests.
107 size_t generate_proof(Digest proof[/*logn+1*/], size_t pos) const {
108 Digest* begin = proof;
109 *proof++ = layers_[pos + n_];
110 for (pos += n_; pos > 1; pos >>= 1) {
111 *proof++ = layers_[pos ^ 1];
112 }
113 return (proof - begin);
114 }
115
116 // Compressed Merkle proofs over a set POS[NP] of leaves.
117 //
118 // We first compute the set TREE of all nodes that are on the path
119 // from the root to any leaf in POS. Then, for each inner node in
120 // TREE, we include in the proof the child that is not in TREE, if
121 // any.
122 size_t generate_compressed_proof(std::vector<Digest>& proof,
123 const size_t pos[/*np*/], size_t np) {
124 std::vector<bool> tree = compressed_merkle_proof_tree(n_, pos, np);
125
126 // For each TREE node, include in the proof the
127 // child that is not TREE, if any.
128 size_t sz = 0;
129 for (size_t i = n_; i-- > 1;) {
130 if (tree[i]) {
131 size_t child = 2 * i;
132 if (tree[child]) {
133 // try the other child
134 child = 2 * i + 1;
135 }
136 if (!tree[child]) {
137 proof.push_back(layers_[child]);
138 ++sz;
139 }
140 }
141 }
142 return sz;
143 }
144
145 size_t n_;
146 // layers_[n, 2 * n) stores the leaves (nodes at layer 0).
147 // layers_[n/2, n) stores nodes at layer 1.
148 // layers_[n/4, n/2) stores nodes at layer 2, etc.
149 // The root is at layers_[1] where layers_[0] is not used.
150 std::vector<Digest> layers_;
151};
152
153class MerkleTreeVerifier {
154 public:
155 explicit MerkleTreeVerifier(size_t n, const Digest& root)
156 : n_(n), root_(root) {}
157
158 bool verify_proof(const Digest* proof, size_t pos) const {
159 Digest t = *proof++;
160 for (pos += n_; pos > 1; pos >>= 1) {
161 t = (pos & 1) ? Digest::hash2(*proof++, t) : Digest::hash2(t, *proof++);
162 }
163 return t == root_;
164 }
165
166 bool verify_compressed_proof(const Digest* proof, size_t proof_len,
167 const Digest leaves[/*np*/],
168 const size_t pos[/*np*/], size_t np) const {
169 // Reconstructed layers_, where only the DEFINED subset is
170 // defined.
171 std::vector<Digest> layers(2 * n_, Digest{});
172 std::vector<bool> defined(2 * n_, false);
173
174 /*scope for TREE */ {
175 std::vector<bool> tree = compressed_merkle_proof_tree(n_, pos, np);
176
177 // read the proof
178 size_t sz = 0;
179 for (size_t i = n_; i-- > 1;) {
180 if (tree[i]) {
181 size_t child = 2 * i;
182 if (tree[child]) {
183 // try the other child
184 child = 2 * i + 1;
185 }
186 if (!tree[child]) {
187 if (sz >= proof_len) {
188 return false;
189 }
190 layers[child] = proof[sz++];
191 defined[child] = true;
192 }
193 }
194 }
195 }
196
197 // set LAYERS at all leaves in POS
198 for (size_t ip = 0; ip < np; ++ip) {
199 size_t l = pos[ip] + n_;
200 layers[l] = leaves[ip];
201 defined[l] = true;
202 }
203
204 // Recompute as many inner nodes as we can
205 for (size_t i = n_; i-- > 1;) {
206 if (defined[2 * i] && defined[2 * i + 1]) {
207 layers[i] = Digest::hash2(layers[2 * i], layers[2 * i + 1]);
208 defined[i] = true;
209 }
210 }
211
212 return (defined[1] && (root_ == layers[1]));
213 }
214
215 private:
216 size_t n_;
217 Digest root_;
218};
219
220} // namespace proofs
221
222#endif // PRIVACY_PROOFS_ZK_LIB_MERKLE_MERKLE_TREE_H_
Definition crypto.h:40
Definition merkle_tree.h:33