23template <
typename Store,
typename HashingPolicy>
class MerkleTree {
80 fr const& value1,
index_t index1,
fr const& value2,
index_t index2,
size_t height,
size_t stump_height);
89 void put(
fr const&
key,
fr const& left,
fr const& right);
114template <
typename T>
inline bool bit_set(T
const& index,
size_t i)
116 return bool((index >> i) & 0x1);
119template <
typename Store,
typename HashingPolicy>
130 auto current =
fr(0);
131 for (
size_t i = 0; i <
depth; ++i) {
133 current = HashingPolicy::hash_pair(current, current);
137template <
typename Store,
typename HashingPolicy>
139 : store_(other.store_)
140 , zero_hashes_(
std::move(other.zero_hashes_))
141 , depth_(other.depth_)
142 , tree_id_(other.tree_id_)
149 std::vector<uint8_t> root;
150 std::vector<uint8_t>
key = { tree_id_ };
151 bool status = store_.get(
key, root);
152 return status ? from_buffer<fr>(root) : HashingPolicy::hash_pair(zero_hashes_.back(), zero_hashes_.back());
155template <
typename Store,
typename HashingPolicy>
158 std::vector<uint8_t> size_buf;
159 std::vector<uint8_t>
key = { tree_id_ };
160 bool status = store_.get(
key, size_buf);
161 return status ? from_buffer<index_t>(size_buf, 32) : 0;
164template <
typename Store,
typename HashingPolicy>
169 std::vector<uint8_t>
data;
172 for (
size_t i = depth_ - 1; i < depth_; --i) {
181 auto left = from_buffer<fr>(
data, 0);
182 auto right = from_buffer<fr>(
data, 32);
184 bool is_right =
bit_set(index, i);
185 auto it =
data.data() + (is_right ? 32 : 0);
186 status = store_.get(std::vector<uint8_t>(it, it + 32),
data);
191 "We store: [key : (value, local_index, true)], i.e. 65-byte data, in a thump.");
192 fr current = from_buffer<fr>(
data, 0);
193 index_t element_index = from_buffer<index_t>(
data, 32);
195 index_t diff = element_index ^ subtree_index;
200 for (
size_t j = 0; j <= i; ++j) {
201 bool is_right =
bit_set(element_index, j);
207 current = HashingPolicy::hash_pair(path[j].first, path[j].second);
214 size_t common_height =
sizeof(
index_t) * 8 - common_bits - 1;
216 for (
size_t j = 0; j < common_height; ++j) {
219 current = compute_zero_path_hash(common_height, element_index, current);
220 for (
size_t j = common_height; j <= i; ++j) {
221 bool is_right =
bit_set(element_index, j);
227 current = HashingPolicy::hash_pair(path[j].first, path[j].second);
237template <
typename Store,
typename HashingPolicy>
242 std::vector<uint8_t>
data;
245 for (
size_t i = depth_ - 1; i < depth_; --i) {
248 path[i] = zero_hashes_[i];
254 bool is_right =
bit_set(index, i);
255 path[i] = from_buffer<fr>(
data, is_right ? 0 : 32);
257 auto it =
data.data() + (is_right ? 32 : 0);
258 status = store_.get(std::vector<uint8_t>(it, it + 32),
data);
263 fr current = from_buffer<fr>(
data, 0);
264 index_t element_index = from_buffer<index_t>(
data, 32);
266 index_t diff = element_index ^ subtree_index;
269 for (
size_t j = 0; j <= i; ++j) {
270 path[j] = zero_hashes_[j];
280 }
else if (diff > 1) {
285 size_t common_height =
sizeof(
index_t) * 8 - common_bits - 1;
288 path[common_height] = compute_zero_path_hash(common_height, element_index, current);
297template <
typename Store,
typename HashingPolicy>
302 std::vector<uint8_t> leaf_key;
303 write(leaf_key, tree_id_);
304 write(leaf_key, index);
307 auto r = update_element(root(), leaf, index, depth_);
309 std::vector<uint8_t> meta_key = { tree_id_ };
310 std::vector<uint8_t> meta_buf;
312 write(meta_buf, index + 1);
313 store_.put(meta_key, meta_buf);
318template <
typename Store,
typename HashingPolicy>
321 bool a_is_right =
bit_set(a_index, height - 1);
322 auto left = a_is_right ?
b :
a;
323 auto right = a_is_right ?
a :
b;
324 auto key = HashingPolicy::hash_pair(left, right);
325 put(
key, left, right);
329template <
typename Store,
typename HashingPolicy>
331 fr const& value1,
index_t index1,
fr const& value2,
index_t index2,
size_t height,
size_t common_height)
333 if (height == common_height) {
337 return binary_put(index1, value1, value2, height);
339 size_t stump_height = height - 1;
343 fr stump1_hash = compute_zero_path_hash(stump_height, stump1_index, value1);
344 fr stump2_hash = compute_zero_path_hash(stump_height, stump2_index, value2);
345 put_stump(stump1_hash, stump1_index, value1);
346 put_stump(stump2_hash, stump2_index, value2);
347 return binary_put(index1, stump1_hash, stump2_hash, height);
350 auto new_root = fork_stump(value1, index1, value2, index2, height - 1, common_height);
351 return binary_put(index1, new_root, zero_hashes_[height - 1], height);
355template <
typename Store,
typename HashingPolicy>
363 std::vector<uint8_t>
data;
367 fr key = compute_zero_path_hash(height, index,
value);
374 index_t existing_index = from_buffer<index_t>(
data, 32);
376 if (existing_index == index) {
378 fr new_hash = compute_zero_path_hash(height, index,
value);
379 put_stump(new_hash, existing_index,
value);
383 fr existing_value = from_buffer<fr>(
data, 0);
385 size_t common_height =
sizeof(
index_t) * 8 - common_bits;
387 return fork_stump(existing_value, existing_index,
value, index, height, common_height);
390 bool is_right =
bit_set(index, height - 1);
391 fr subtree_root = from_buffer<fr>(
data, is_right ? 32 : 0);
392 fr subtree_root_copy = subtree_root;
393 auto left = from_buffer<fr>(
data, 0);
394 auto right = from_buffer<fr>(
data, 32);
397 right = subtree_root;
401 auto new_root = HashingPolicy::hash_pair(left, right);
402 put(new_root, left, right);
405 if (!(subtree_root_copy == subtree_root)) {
406 remove(subtree_root_copy);
412template <
typename Store,
typename HashingPolicy>
416 for (
size_t i = 0; i < height; ++i) {
417 bool is_right =
bit_set(index, i);
420 left = zero_hashes_[i];
423 right = zero_hashes_[i];
426 current = HashingPolicy::hash_pair(left, right);
431template <
typename Store,
typename HashingPolicy>
434 std::vector<uint8_t>
value;
440template <
typename Store,
typename HashingPolicy>
443 std::vector<uint8_t>
buf;
#define BB_ASSERT_GTE(left, right,...)
#define BB_ASSERT_EQ(actual, expected,...)
#define BB_ASSERT_LTE(left, right,...)
void remove(fr const &key)
MerkleTree(MerkleTree const &other)=delete
void put_stump(fr const &key, index_t index, fr const &value)
void put(fr const &key, fr const &left, fr const &right)
std::vector< fr > zero_hashes_
fr fork_stump(fr const &value1, index_t index1, fr const &value2, index_t index2, size_t height, size_t stump_height)
MerkleTree(Store &store, size_t depth, uint8_t tree_id=0)
fr_hash_path get_hash_path(index_t index)
fr compute_zero_path_hash(size_t height, index_t index, fr const &value)
fr binary_put(index_t a_index, fr const &a, fr const &b, size_t height)
fr get_element(fr const &root, index_t index, size_t height)
fr_sibling_path get_sibling_path(index_t index)
fr update_element(index_t index, fr const &value)
const std::vector< FF > data
ContentAddressedCachedTreeStore< bb::fr > Store
constexpr size_t STUMP_NODE_SIZE
constexpr size_t REGULAR_NODE_SIZE
std::vector< std::pair< fr, fr > > fr_hash_path
std::vector< fr > fr_sibling_path
bool bit_set(T const &index, size_t i)
constexpr size_t count_leading_zeros(T const &u)
T keep_n_lsb(T const &input, size_t num_bits)
field< Bn254FrParams > fr
void write(B &buf, field2< base_field, Params > const &value)
void write(auto &buf, const msgpack_concepts::HasMsgPack auto &obj)
Automatically derived write for any object that defines .msgpack() (implicitly defined by MSGPACK_FIE...
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
std::vector< uint8_t > to_buffer(T const &value)
BB_INLINE std::vector< uint8_t > to_buffer() const