Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
public_data_tree_check.cpp
Go to the documentation of this file.
2
3#include <algorithm>
4#include <limits>
5#include <stdexcept>
6
9
10namespace bb::avm2::simulation {
11
20{
21 return poseidon2.hash({ DOM_SEP__PUBLIC_LEAF_SLOT, contract_address, slot });
22}
23
36 const FF& leaf_slot)
37{
38 if (!field_gt.ff_gt(leaf_slot, low_leaf_preimage.leaf.slot)) {
39 throw std::runtime_error("Low leaf slot is GTE leaf slot");
40 }
41 // indexed_leaf calls nextKey/nextSlot as nextValue, which is counter intuitive in public data tree
42 if (low_leaf_preimage.nextKey != 0 && !field_gt.ff_gt(low_leaf_preimage.nextKey, leaf_slot)) {
43 throw std::runtime_error("Leaf slot is GTE low leaf next slot");
44 }
45}
46
64 const AztecAddress& contract_address,
65 const FF& value,
66 const PublicDataTreeLeafPreimage& low_leaf_preimage,
67 uint64_t low_leaf_index,
68 std::span<const FF> sibling_path,
69 const AppendOnlyTreeSnapshot& snapshot)
70{
71 FF leaf_slot = compute_leaf_slot(contract_address, slot);
72 // Low leaf membership
73 FF low_leaf_hash = poseidon2.hash(low_leaf_preimage.get_hash_inputs());
74 merkle_check.assert_membership(
75 DOM_SEP__PUBLIC_DATA_MERKLE, low_leaf_hash, low_leaf_index, sibling_path, snapshot.root);
76
77 // Low leaf and value validation
78 bool exists = low_leaf_preimage.leaf.slot == leaf_slot;
79 if (exists) {
80 if (low_leaf_preimage.leaf.value != value) {
81 throw std::runtime_error("Leaf value does not match value");
82 }
83 } else {
84 validate_low_leaf_jumps_over_slot(low_leaf_preimage, leaf_slot);
85
86 if (value != 0) {
87 throw std::runtime_error("Value is nonzero for a non existing slot");
88 }
89 }
90
92 .contract_address = contract_address,
93 .slot = slot,
94 .value = value,
95 .leaf_slot = leaf_slot,
96 .prev_snapshot = snapshot,
97 .low_leaf_preimage = low_leaf_preimage,
98 .low_leaf_hash = low_leaf_hash,
99 .low_leaf_index = low_leaf_index,
100 });
101}
102
122 const AztecAddress& contract_address,
123 const FF& value,
124 const PublicDataTreeLeafPreimage& low_leaf_preimage,
125 uint64_t low_leaf_index,
126 std::span<const FF> low_leaf_sibling_path,
127 const AppendOnlyTreeSnapshot& prev_snapshot,
128 std::span<const FF> insertion_sibling_path,
129 bool is_protocol_write)
130{
131 FF leaf_slot = compute_leaf_slot(contract_address, slot);
132 // Validate low leaf
133 bool exists = low_leaf_preimage.leaf.slot == leaf_slot;
134 if (!exists) {
135 validate_low_leaf_jumps_over_slot(low_leaf_preimage, leaf_slot);
136 }
137
138 // Low leaf update
139 FF low_leaf_hash = poseidon2.hash(low_leaf_preimage.get_hash_inputs());
140
141 PublicDataTreeLeafPreimage updated_low_leaf_preimage = low_leaf_preimage;
142 if (exists) {
143 // Update value
144 updated_low_leaf_preimage.leaf.value = value;
145 } else {
146 // Update pointers
147 updated_low_leaf_preimage.nextIndex = prev_snapshot.next_available_leaf_index;
148 updated_low_leaf_preimage.nextKey = leaf_slot;
149 }
150
151 FF updated_low_leaf_hash = poseidon2.hash(updated_low_leaf_preimage.get_hash_inputs());
152
153 FF intermediate_root = merkle_check.write(DOM_SEP__PUBLIC_DATA_MERKLE,
154 low_leaf_hash,
155 updated_low_leaf_hash,
156 low_leaf_index,
157 low_leaf_sibling_path,
158 prev_snapshot.root);
159
161 .root = intermediate_root,
162 .next_available_leaf_index = prev_snapshot.next_available_leaf_index,
163 };
164 FF new_leaf_hash = 0;
166 if (!exists) {
167 // Insert new leaf
169 PublicDataLeafValue(leaf_slot, value), low_leaf_preimage.nextIndex, low_leaf_preimage.nextKey);
170
171 new_leaf_hash = poseidon2.hash(new_leaf.get_hash_inputs());
172 next_snapshot.root = merkle_check.write(DOM_SEP__PUBLIC_DATA_MERKLE,
173 FF(0),
174 new_leaf_hash,
175 prev_snapshot.next_available_leaf_index,
176 insertion_sibling_path,
177 intermediate_root);
178 next_snapshot.next_available_leaf_index++;
179 }
180
181 // The protocol writes happen outside execution, at the end of the tx simulation.
182 uint32_t execution_id =
183 is_protocol_write ? std::numeric_limits<uint32_t>::max() : execution_id_manager.get_execution_id();
184
186 .contract_address = contract_address,
187 .slot = slot,
188 .value = value,
189 .leaf_slot = leaf_slot,
190 .prev_snapshot = prev_snapshot,
191 .low_leaf_preimage = low_leaf_preimage,
192 .low_leaf_hash = low_leaf_hash,
193 .low_leaf_index = low_leaf_index,
194 .write_data = PublicDataWriteData{ .updated_low_leaf_preimage = updated_low_leaf_preimage,
195 .updated_low_leaf_hash = updated_low_leaf_hash,
196 .new_leaf_hash = new_leaf_hash,
197 .intermediate_root = intermediate_root,
198 .next_snapshot = next_snapshot },
199 .execution_id = execution_id,
200 });
201
202 return next_snapshot;
203}
204
212
220
228
234void PublicDataTreeCheck::generate_ff_gt_events_for_squashing(const std::vector<FF>& written_leaf_slots)
235{
236 // We need the sorted leaf slots to generate the ff_gt events in order.
237 std::vector<FF> sorted_written_leaf_slots = written_leaf_slots;
238 // Leaf slot needs to be casted as uint256_t to compare.
239 // Sorting over pointers instead of structs would be faster but probably negligible for such a small vector.
240 std::ranges::sort(sorted_written_leaf_slots,
241 [](const FF& a, const FF& b) { return static_cast<uint256_t>(a) < static_cast<uint256_t>(b); });
242
243 if (sorted_written_leaf_slots.size() > 1) {
244 for (size_t i = 0; i < sorted_written_leaf_slots.size() - 1; i++) {
245 field_gt.ff_gt(sorted_written_leaf_slots.at(i + 1), sorted_written_leaf_slots.at(i));
246 }
247 }
248}
249
250} // namespace bb::avm2::simulation
#define DOM_SEP__PUBLIC_LEAF_SLOT
#define DOM_SEP__PUBLIC_DATA_MERKLE
virtual void emit(Event &&event)=0
virtual uint32_t get_execution_id() const =0
virtual bool ff_gt(const FF &a, const FF &b)=0
void on_checkpoint_created() override
Emit a checkpoint-created event for discard reconstruction.
FF compute_leaf_slot(const AztecAddress &contract_address, const FF &slot)
Compute the siloed leaf slot from a contract address and storage slot.
void validate_low_leaf_jumps_over_slot(const PublicDataTreeLeafPreimage &low_leaf_preimage, const FF &leaf_slot)
Validate that the low leaf's slot range covers (jumps over) the given leaf slot.
AppendOnlyTreeSnapshot write(const FF &slot, const AztecAddress &contract_address, const FF &value, const PublicDataTreeLeafPreimage &low_leaf_preimage, uint64_t low_leaf_index, std::span< const FF > low_leaf_sibling_path, const AppendOnlyTreeSnapshot &prev_snapshot, std::span< const FF > insertion_sibling_path, bool is_protocol_write) override
Write a value to the public data tree.
void on_checkpoint_committed() override
Emit a checkpoint-committed event for discard reconstruction.
void generate_ff_gt_events_for_squashing(const std::vector< FF > &written_leaf_slots)
Generates ff_gt events for squashing.
void on_checkpoint_reverted() override
Emit a checkpoint-reverted event for discard reconstruction.
void assert_read(const FF &slot, const AztecAddress &contract_address, const FF &value, const PublicDataTreeLeafPreimage &low_leaf_preimage, uint64_t low_leaf_index, std::span< const FF > sibling_path, const AppendOnlyTreeSnapshot &snapshot) override
Assert that a public data tree read is valid.
EventEmitterInterface< PublicDataTreeCheckEvent > & events
static FF hash(const std::vector< FF > &input)
Hashes a vector of field elements.
FF a
FF b
AVM range check gadget for witness generation.
IndexedLeaf< PublicDataLeafValue > PublicDataTreeLeafPreimage
::bb::crypto::merkle_tree::PublicDataLeafValue PublicDataLeafValue
Definition db.hpp:38
AvmFlavorSettings::FF FF
Definition field.hpp:10
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
static IndexedLeaf< PublicDataLeafValue > empty()
std::vector< fr > get_hash_inputs() const