barretenberg
Loading...
Searching...
No Matches
membership.hpp
1#pragma once
2#include "barretenberg/stdlib/hash/pedersen/pedersen.hpp"
3#include "barretenberg/stdlib/primitives/byte_array/byte_array.hpp"
4#include "barretenberg/stdlib/primitives/field/field.hpp"
5#include "hash_path.hpp"
6
7namespace proof_system::plonk {
8namespace stdlib {
9namespace merkle_tree {
10
11template <typename Builder> using bit_vector = std::vector<bool_t<Builder>>;
25template <typename Builder>
26field_t<Builder> compute_subtree_root(hash_path<Builder> const& hashes,
27 field_t<Builder> const& value,
28 bit_vector<Builder> const& index,
29 size_t at_height,
30 bool const is_updating_tree = false)
31{
32 auto current = value;
33 for (size_t i = at_height; i < hashes.size(); ++i) {
34 // get the parity bit at this level of the tree (get_bit returns bool so we know this is 0 or 1)
35 bool_t<Builder> path_bit = index[i];
36
37 // reconstruct the two inputs we need to hash
38 // if `path_bit = false`, we know `current` is the left leaf and `hashes[i].second` is the right leaf
39 // if `path_bit = true`, we know `current` is the right leaf and `hashes[i].first` is the left leaf
40 // We don't need to explicitly check that hashes[i].first = current iff !path bit , or that hashes[i].second =
41 // current iff path_bit If either of these does not hold, then the final computed merkle root will not match
42 field_t<Builder> left = field_t<Builder>::conditional_assign(path_bit, hashes[i].first, current);
43 field_t<Builder> right = field_t<Builder>::conditional_assign(path_bit, current, hashes[i].second);
44 if (is_updating_tree) {
45 current = pedersen_hash<Builder>::hash({ left, right }, 0);
46 } else {
47 current = pedersen_hash<Builder>::hash_skip_field_validation({ left, right }, 0);
48 }
49 }
50
51 return current;
52}
53
68template <typename Builder>
69bool_t<Builder> check_subtree_membership(field_t<Builder> const& root,
70 hash_path<Builder> const& hashes,
71 field_t<Builder> const& value,
72 bit_vector<Builder> const& index,
73 size_t at_height,
74 bool const is_updating_tree = false)
75{
76 return (compute_subtree_root(hashes, value, index, at_height, is_updating_tree) == root);
77}
78
92template <typename Builder>
93void assert_check_subtree_membership(field_t<Builder> const& root,
94 hash_path<Builder> const& hashes,
95 field_t<Builder> const& value,
96 bit_vector<Builder> const& index,
97 size_t at_height,
98 bool const is_updating_tree = false,
99 std::string const& msg = "assert_check_subtree_membership")
100{
101 auto exists = check_subtree_membership(root, hashes, value, index, at_height, is_updating_tree);
102 exists.assert_equal(true, msg);
103}
104
116template <typename Builder>
117bool_t<Builder> check_membership(field_t<Builder> const& root,
118 hash_path<Builder> const& hashes,
119 field_t<Builder> const& value,
120 bit_vector<Builder> const& index,
121 bool const is_updating_tree = false)
122{
123 return check_subtree_membership(root, hashes, value, index, 0, is_updating_tree);
124}
125
138template <typename Builder>
139void assert_check_membership(field_t<Builder> const& root,
140 hash_path<Builder> const& hashes,
141 field_t<Builder> const& value,
142 bit_vector<Builder> const& index,
143 bool const is_updating_tree = false,
144 std::string const& msg = "assert_check_membership")
145{
146 auto exists = stdlib::merkle_tree::check_membership(root, hashes, value, index, is_updating_tree);
147 exists.assert_equal(true, msg);
148}
149
163template <typename Builder>
164void update_membership(field_t<Builder> const& new_root,
165 field_t<Builder> const& new_value,
166 field_t<Builder> const& old_root,
167 hash_path<Builder> const& old_hashes,
168 field_t<Builder> const& old_value,
169 bit_vector<Builder> const& index,
170 std::string const& msg = "update_membership")
171{
172 // Check that the old_value, is in the tree given by old_root, at index.
173 assert_check_membership(old_root, old_hashes, old_value, index, false, msg + "_old_value");
174
175 // Check that the new_value, is in the tree given by new_root, at index.
176 assert_check_membership(new_root, old_hashes, new_value, index, true, msg + "_new_value");
177}
178
190template <typename Builder>
191field_t<Builder> update_memberships(field_t<Builder> old_root,
192 std::vector<field_t<Builder>> const& new_roots,
193 std::vector<field_t<Builder>> const& new_values,
194 std::vector<field_t<Builder>> const& old_values,
195 std::vector<hash_path<Builder>> const& old_paths,
196 std::vector<bit_vector<Builder>> const& old_indicies)
197{
198 for (size_t i = 0; i < old_indicies.size(); i++) {
199 update_membership(
200 new_roots[i], new_values[i], old_root, old_paths[i], old_values[i], old_indicies[i], "update_memberships");
201
202 old_root = new_roots[i];
203 }
204
205 return old_root;
206}
207
222template <typename Builder>
223void update_subtree_membership(field_t<Builder> const& new_root,
224 field_t<Builder> const& new_subtree_root,
225 field_t<Builder> const& old_root,
226 hash_path<Builder> const& old_hashes,
227 field_t<Builder> const& old_subtree_root,
228 bit_vector<Builder> const& index,
229 size_t at_height,
230 std::string const& msg = "update_subtree_membership")
231{
232 // Check that the old_subtree_root, is in the tree given by old_root, at index and at_height.
233 assert_check_subtree_membership(
234 old_root, old_hashes, old_subtree_root, index, at_height, false, msg + "_old_subtree");
235
236 // Check that the new_subtree_root, is in the tree given by new_root, at index and at_height.
237 // By extracting partner hashes from `old_hashes`, we also validate both membership proofs use
238 // identical merkle trees (apart from the leaf that is being updated)
239 assert_check_subtree_membership(
240 new_root, old_hashes, new_subtree_root, index, at_height, true, msg + "_new_subtree");
241}
242
249template <typename Builder> field_t<Builder> compute_tree_root(std::vector<field_t<Builder>> const& input)
250{
251 // Check if the input vector size is a power of 2.
252 ASSERT(input.size() > 0);
253 ASSERT(!(input.size() & (input.size() - 1)) == true);
254 auto layer = input;
255 while (layer.size() > 1) {
256 std::vector<field_t<Builder>> next_layer(layer.size() / 2);
257 for (size_t i = 0; i < next_layer.size(); ++i) {
258 next_layer[i] = pedersen_hash<Builder>::hash({ layer[i * 2], layer[i * 2 + 1] });
259 }
260 layer = std::move(next_layer);
261 }
262
263 return layer[0];
264}
265
272template <typename Builder>
273bool_t<Builder> check_tree(field_t<Builder> const& root, std::vector<field_t<Builder>> const& values)
274{
275 return compute_tree_root(values) == root;
276}
277
284template <typename Builder>
285void assert_check_tree(field_t<Builder> const& root, std::vector<field_t<Builder>> const& values)
286{
287 auto valid = check_tree(root, values);
288 valid.assert_equal(true, "assert_check_tree");
289}
290
302template <typename Builder>
303void batch_update_membership(field_t<Builder> const& new_root,
304 field_t<Builder> const& old_root,
305 hash_path<Builder> const& old_path,
306 std::vector<field_t<Builder>> const& new_values,
307 field_t<Builder> const& start_index,
308 std::string const& msg = "batch_update_membership")
309{
310 size_t height = numeric::get_msb(new_values.size());
311 auto zero_subtree_root = field_t<Builder>(zero_hash_at_height(height));
312
313 auto rollup_root = compute_tree_root(new_values);
314
315 update_subtree_membership(
316 new_root, rollup_root, old_root, old_path, zero_subtree_root, start_index.decompose_into_bits(), height, msg);
317}
318
319} // namespace merkle_tree
320} // namespace stdlib
321} // namespace proof_system::plonk
Definition: field.hpp:10
std::vector< bool_t< Builder > > decompose_into_bits(size_t num_bits=256, std::function< witness_t< Builder >(Builder *ctx, uint64_t, uint256_t)> get_bit=[](Builder *ctx, uint64_t j, const uint256_t &val) { return witness_t< Builder >(ctx, val.get_bit(j));}) const
Build a circuit allowing a user to prove that they have deomposed this into bits.
Definition: field.cpp:1090
Definition: widget.bench.cpp:13