Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
merkle_check.cpp
Go to the documentation of this file.
2
3#include <cassert>
4#include <cstdint>
5
7
8namespace bb::avm2::simulation {
9
10void MerkleCheck::assert_membership(const FF& leaf_value,
11 const uint64_t leaf_index,
12 std::span<const FF> sibling_path,
13 const FF& root)
14{
15 // Gadget breaks if tree_height >= 254
16 assert(sibling_path.size() <= 254 && "Merkle path length must be less than 254");
17
18 FF curr_value = leaf_value;
19 uint64_t curr_index = leaf_index;
20 // for (const auto& i : sibling_path) {
21 for (size_t i = 0; i < sibling_path.size(); ++i) {
22 const FF sibling = sibling_path[i];
23 bool index_is_even = (curr_index % 2 == 0);
24
25 curr_value = index_is_even ? poseidon2.hash({ curr_value, sibling }) : poseidon2.hash({ sibling, curr_value });
26
27 // Halve the index (to get the parent index) as we move up the tree>
28 // Don't halve on the last iteration because after the loop,
29 // we want curr_index to be the "final" index (0 or 1).
30 if (i < sibling_path.size() - 1) {
31 curr_index >>= 1;
32 }
33 }
34
35 if (curr_index != 0 && curr_index != 1) {
36 throw std::runtime_error("Merkle check's final node index must be 0 or 1");
37 }
38 if (curr_value != root) {
39 throw std::runtime_error("Merkle read check failed");
40 }
41
42 std::vector<FF> sibling_vec(sibling_path.begin(), sibling_path.end());
43 events.emit(
44 { .leaf_value = leaf_value, .leaf_index = leaf_index, .sibling_path = std::move(sibling_vec), .root = root });
45}
46
47FF MerkleCheck::write(const FF& current_value,
48 const FF& new_value,
49 const uint64_t leaf_index,
50 std::span<const FF> sibling_path,
51 const FF& current_root)
52{
53 // Gadget breaks if tree_height >= 254
54 assert(sibling_path.size() <= 254 && "Merkle path length must be less than 254");
55
56 FF read_value = current_value;
57 FF write_value = new_value;
58 uint64_t curr_index = leaf_index;
59
60 for (size_t i = 0; i < sibling_path.size(); ++i) {
61 const FF sibling = sibling_path[i];
62 bool index_is_even = (curr_index % 2 == 0);
63
64 read_value = index_is_even ? poseidon2.hash({ read_value, sibling }) : poseidon2.hash({ sibling, read_value });
65 write_value =
66 index_is_even ? poseidon2.hash({ write_value, sibling }) : poseidon2.hash({ sibling, write_value });
67
68 // Halve the index (to get the parent index) as we move up the tree>
69 // Don't halve on the last iteration because after the loop,
70 // we want curr_index to be the "final" index (0 or 1).
71 if (i < sibling_path.size() - 1) {
72 curr_index >>= 1;
73 }
74 }
75
76 if (curr_index != 0 && curr_index != 1) {
77 throw std::runtime_error("Merkle check's final node index must be 0 or 1");
78 }
79 if (read_value != current_root) {
80 throw std::runtime_error("Merkle read check failed");
81 }
82
83 std::vector<FF> sibling_vec(sibling_path.begin(), sibling_path.end());
84 events.emit({ .leaf_value = current_value,
85 .new_leaf_value = new_value,
86 .leaf_index = leaf_index,
87 .sibling_path = std::move(sibling_vec),
88 .root = current_root,
89 .new_root = write_value });
90
91 return write_value;
92}
93
94} // namespace bb::avm2::simulation
FF write(const FF &current_value, const FF &new_value, const uint64_t leaf_index, std::span< const FF > sibling_path, const FF &current_root) override
void assert_membership(const FF &leaf_value, const uint64_t leaf_index, std::span< const FF > sibling_path, const FF &root) override
EventEmitterInterface< MerkleCheckEvent > & events
static FF hash(const std::vector< FF > &input)
Hashes a vector of field elements.
AvmFlavorSettings::FF FF
Definition field.hpp:10
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13