Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
concrete_dbs.cpp
Go to the documentation of this file.
2
6
7namespace bb::avm2::simulation {
8
9// Contracts DB starts.
11{
13 // If we didn't get a contract instance, we don't prove anything.
14 // It is the responsibility of the caller to prove what the protocol expects.
15 if (!instance.has_value()) {
16 return std::nullopt;
17 }
18 // If we did get a contract instance, we need to prove that the address is derived from the instance.
19 // For protocol contracts the input address is the canonical address, we need to retrieve the derived address.
20 AztecAddress derived_address = is_protocol_contract_address(address)
22 .value() /* We can assume that get_derived_address will not return a
23 nullopt, since we have succesfully fetched the instance.*/
24 : address;
25 address_derivation.assert_derivation(derived_address, instance.value());
26 return instance;
27}
28
30{
32 // If we didn't get a contract class, we don't prove anything.
33 // It is the responsibility of the caller to prove what the protocol expects.
34 if (!klass.has_value()) {
35 return std::nullopt;
36 }
37 // If we did get a contract class, we need to prove that the class_id is derived from the class.
38 class_id_derivation.assert_derivation(class_id, klass.value());
39 return klass;
40}
41
42// Merkle DB starts.
43
45{
46 // No event generated.
48 TreeCounters tree_counters = tree_counters_stack.top();
49 return {
50 .noteHashTree = { .tree = tree_snapshots.noteHashTree, .counter = tree_counters.note_hash_counter },
51 .nullifierTree = { .tree = tree_snapshots.nullifierTree, .counter = tree_counters.nullifier_counter },
52 .l1ToL2MessageTree = { .tree = tree_snapshots.l1ToL2MessageTree,
53 .counter = tree_counters.l2_to_l1_msg_counter },
54 .publicDataTree = { .tree = tree_snapshots.publicDataTree, .counter = written_public_data_slots.size() },
55 };
56}
57
59{
60 auto [present, index] = raw_merkle_db.get_low_indexed_leaf(MerkleTreeId::PUBLIC_DATA_TREE,
62 auto path = raw_merkle_db.get_sibling_path(MerkleTreeId::PUBLIC_DATA_TREE, index);
64
65 FF value = present ? preimage.leaf.value : 0;
66
69
70 return value;
71}
72
74 const FF& slot,
75 const FF& value,
76 bool is_protocol_write)
77{
80
82
83 auto& low_leaf_hint = hint.low_leaf_witness_data.at(0);
84 auto& insertion_hint = hint.insertion_witness_data.at(0);
85
88 value,
89 low_leaf_hint.leaf,
90 low_leaf_hint.index,
91 low_leaf_hint.path,
92 snapshot_before,
93 insertion_hint.path,
94 is_protocol_write);
95
96 (void)snapshot_after; // Silence unused variable warning when assert is stripped out
97 // Sanity check.
98 assert(snapshot_after == raw_merkle_db.get_tree_roots().publicDataTree);
99 if (!is_protocol_write) {
101 }
102}
103
108
113
115{
116 return nullifier_exists_internal(/*contract_address*/ std::nullopt, nullifier);
117}
118
120{
121 FF siloed_nullifier = nullifier;
122 if (contract_address.has_value()) {
123 // Unconstrained siloing to fetch the hint, since the hints are keyed by siloed data.
124 // The siloing will later be constrained in the nullifier tree check gadget.
125 siloed_nullifier = unconstrained_silo_nullifier(contract_address.value(), nullifier);
126 }
127
128 auto [present, low_leaf_index] = raw_merkle_db.get_low_indexed_leaf(MerkleTreeId::NULLIFIER_TREE, siloed_nullifier);
129 auto low_leaf_path = raw_merkle_db.get_sibling_path(MerkleTreeId::NULLIFIER_TREE, low_leaf_index);
130 auto low_leaf_preimage = raw_merkle_db.get_leaf_preimage_nullifier_tree(low_leaf_index);
131
134 present,
135 low_leaf_preimage,
136 low_leaf_index,
137 low_leaf_path,
139
140 return present;
141}
142
147
149{
150 return nullifier_write_internal(/*contract_address*/ std::nullopt, nullifier);
151}
152
154{
155 uint32_t nullifier_counter = tree_counters_stack.top().nullifier_counter;
156 FF siloed_nullifier = nullifier;
157 if (contract_address.has_value()) {
158 // Unconstrained siloing to fetch the hint, since the hints are keyed by siloed data.
159 // The siloing will later be constrained in the nullifier tree check gadget.
160 siloed_nullifier = unconstrained_silo_nullifier(contract_address.value(), nullifier);
161 }
162
163 auto [present, low_leaf_index] = raw_merkle_db.get_low_indexed_leaf(MerkleTreeId::NULLIFIER_TREE, siloed_nullifier);
165
166 SiblingPath low_leaf_path;
167 IndexedLeaf<NullifierLeafValue> low_leaf_preimage;
169
170 if (present) {
171 low_leaf_path = raw_merkle_db.get_sibling_path(MerkleTreeId::NULLIFIER_TREE, low_leaf_index);
172 low_leaf_preimage = raw_merkle_db.get_leaf_preimage_nullifier_tree(low_leaf_index);
173 } else {
174 auto insertion_result = raw_merkle_db.insert_indexed_leaves_nullifier_tree(siloed_nullifier);
175
176 low_leaf_path = insertion_result.low_leaf_witness_data.at(0).path;
177 low_leaf_preimage = insertion_result.low_leaf_witness_data.at(0).leaf;
178 insertion_path = insertion_result.insertion_witness_data.at(0).path;
179 }
180
183 nullifier_counter,
184 low_leaf_preimage,
185 low_leaf_index,
186 low_leaf_path,
187 snapshot_before,
188 insertion_path);
189
190 (void)snapshot_after; // Silence unused variable warning when assert is stripped out
191 // Sanity check.
192 assert(snapshot_after == raw_merkle_db.get_tree_roots().nullifierTree);
193
194 if (!present) {
195 tree_counters_stack.top().nullifier_counter++;
196 } else {
197 throw NullifierCollisionException(format("Nullifier ", nullifier, " already exists"));
198 }
199}
200
201bool MerkleDB::note_hash_exists(uint64_t leaf_index, const FF& unique_note_hash) const
202{
203 auto leaf_value = raw_merkle_db.get_leaf_value(MerkleTreeId::NOTE_HASH_TREE, leaf_index);
204 auto path = raw_merkle_db.get_sibling_path(MerkleTreeId::NOTE_HASH_TREE, leaf_index);
205 return note_hash_tree_check.note_hash_exists(
206 unique_note_hash, leaf_value, leaf_index, path, raw_merkle_db.get_tree_roots().noteHashTree);
207}
208
210{
211 uint32_t note_hash_counter = tree_counters_stack.top().note_hash_counter;
212
214 // Unconstrained siloing and uniqueness to fetch the hint, since the hints are keyed by the unique note hash.
215 // The siloing and uniqueness will later be constrained in the note hash tree check gadget.
216 FF siloed_note_hash = unconstrained_silo_note_hash(contract_address, note_hash);
217 FF unique_note_hash = unconstrained_make_unique_note_hash(
218 siloed_note_hash, note_hash_tree_check.get_first_nullifier(), note_hash_counter);
219 auto append_result =
220 raw_merkle_db.append_leaves(MerkleTreeId::NOTE_HASH_TREE, std::vector<FF>{ unique_note_hash })[0];
221
222 AppendOnlyTreeSnapshot snapshot_after = note_hash_tree_check.append_note_hash(
223 note_hash, contract_address, note_hash_counter, append_result.path, snapshot_before);
224
225 (void)snapshot_after; // Silence unused variable warning when assert is stripped out
226 // Sanity check.
227 assert(snapshot_after == raw_merkle_db.get_tree_roots().noteHashTree);
228
229 tree_counters_stack.top().note_hash_counter++;
230}
231
232void MerkleDB::siloed_note_hash_write(const FF& siloed_note_hash)
233{
234 uint32_t note_hash_counter = tree_counters_stack.top().note_hash_counter;
236 // Unconstrained siloing and uniqueness to fetch the hint, since the hints are keyed by the unique note hash.
237 // The siloing and uniqueness will later be constrained in the note hash tree check gadget.
238 FF unique_note_hash = unconstrained_make_unique_note_hash(
239 siloed_note_hash, note_hash_tree_check.get_first_nullifier(), note_hash_counter);
240 auto hint = raw_merkle_db.append_leaves(MerkleTreeId::NOTE_HASH_TREE, std::vector<FF>{ unique_note_hash })[0];
241
242 AppendOnlyTreeSnapshot snapshot_after =
243 note_hash_tree_check.append_siloed_note_hash(siloed_note_hash, note_hash_counter, hint.path, snapshot_before);
244
245 (void)snapshot_after; // Silence unused variable warning when assert is stripped out
246 // Sanity check.
247 assert(snapshot_after == raw_merkle_db.get_tree_roots().noteHashTree);
248
249 tree_counters_stack.top().note_hash_counter++;
250}
251
252void MerkleDB::unique_note_hash_write(const FF& unique_note_hash)
253{
254 uint32_t note_hash_counter = tree_counters_stack.top().note_hash_counter;
256 auto hint = raw_merkle_db.append_leaves(MerkleTreeId::NOTE_HASH_TREE, std::vector<FF>{ unique_note_hash })[0];
257
258 AppendOnlyTreeSnapshot snapshot_after =
259 note_hash_tree_check.append_unique_note_hash(unique_note_hash, note_hash_counter, hint.path, snapshot_before);
260
261 (void)snapshot_after; // Silence unused variable warning when assert is stripped out
262 // Sanity check.
263 assert(snapshot_after == raw_merkle_db.get_tree_roots().noteHashTree);
264
265 tree_counters_stack.top().note_hash_counter++;
266}
267
268bool MerkleDB::l1_to_l2_msg_exists(uint64_t leaf_index, const FF& msg_hash) const
269{
270 auto leaf_value = raw_merkle_db.get_leaf_value(MerkleTreeId::L1_TO_L2_MESSAGE_TREE, leaf_index);
271 auto path = raw_merkle_db.get_sibling_path(MerkleTreeId::L1_TO_L2_MESSAGE_TREE, leaf_index);
273 msg_hash, leaf_value, leaf_index, path, raw_merkle_db.get_tree_roots().l1ToL2MessageTree);
274}
275
277{
278 // The public data tree is not padded.
279 raw_merkle_db.pad_tree(MerkleTreeId::NOTE_HASH_TREE,
280 MAX_NOTE_HASHES_PER_TX - tree_counters_stack.top().note_hash_counter);
281 raw_merkle_db.pad_tree(MerkleTreeId::NULLIFIER_TREE,
282 MAX_NULLIFIERS_PER_TX - tree_counters_stack.top().nullifier_counter);
283}
284
286{
290 for (auto& listener : checkpoint_listeners) {
291 listener->on_checkpoint_created();
292 }
293}
294
296{
299 TreeCounters current_counters = tree_counters_stack.top();
301 tree_counters_stack.top() = current_counters;
302 for (auto& listener : checkpoint_listeners) {
303 listener->on_checkpoint_committed();
304 }
305}
306
308{
312 for (auto& listener : checkpoint_listeners) {
313 listener->on_checkpoint_reverted();
314 }
315}
316
318{
320}
321
322} // namespace bb::avm2::simulation
#define MAX_NOTE_HASHES_PER_TX
#define MAX_NULLIFIERS_PER_TX
ContractDBInterface & raw_contract_db
std::optional< ContractInstance > get_contract_instance(const AztecAddress &address) const override
const ProtocolContracts & protocol_contracts
std::optional< ContractClass > get_contract_class(const ContractClassId &class_id) const override
virtual std::optional< ContractInstance > get_contract_instance(const AztecAddress &address) const =0
virtual std::optional< ContractClass > get_contract_class(const ContractClassId &class_id) const =0
virtual bool exists(const FF &msg_hash, const FF &leaf_value, uint64_t leaf_index, std::span< const FF > sibling_path, const AppendOnlyTreeSnapshot &snapshot)=0
virtual IndexedLeaf< PublicDataLeafValue > get_leaf_preimage_public_data_tree(index_t leaf_index) const =0
virtual std::vector< AppendLeafResult > append_leaves(MerkleTreeId tree_id, std::span< const FF > leaves)=0
virtual void pad_tree(MerkleTreeId tree_id, size_t num_leaves)=0
virtual IndexedLeaf< NullifierLeafValue > get_leaf_preimage_nullifier_tree(index_t leaf_index) const =0
virtual SequentialInsertionResult< NullifierLeafValue > insert_indexed_leaves_nullifier_tree(const NullifierLeafValue &leaf_value)=0
virtual GetLowIndexedLeafResponse get_low_indexed_leaf(MerkleTreeId tree_id, const FF &value) const =0
virtual SiblingPath get_sibling_path(MerkleTreeId tree_id, index_t leaf_index) const =0
virtual uint32_t get_checkpoint_id() const =0
virtual SequentialInsertionResult< PublicDataLeafValue > insert_indexed_leaves_public_data_tree(const PublicDataLeafValue &leaf_value)=0
virtual const TreeSnapshots & get_tree_roots() const =0
virtual FF get_leaf_value(MerkleTreeId tree_id, index_t leaf_index) const =0
WrittenPublicDataSlotsInterface & written_public_data_slots
void note_hash_write(const AztecAddress &contract_address, const FF &note_hash) override
std::vector< CheckpointNotifiable * > checkpoint_listeners
std::stack< TreeCounters > tree_counters_stack
bool nullifier_exists(const AztecAddress &contract_address, const FF &nullifier) const override
LowLevelMerkleDBInterface & raw_merkle_db
void unique_note_hash_write(const FF &note_hash) override
void nullifier_write_internal(std::optional< AztecAddress > contract_address, const FF &nullifier)
TreeStates get_tree_state() const override
bool was_storage_written(const AztecAddress &contract_address, const FF &slot) const override
NullifierTreeCheckInterface & nullifier_tree_check
uint32_t get_checkpoint_id() const override
bool note_hash_exists(uint64_t leaf_index, const FF &unique_note_hash) const override
void siloed_note_hash_write(const FF &note_hash) override
void siloed_nullifier_write(const FF &nullifier) override
FF storage_read(const AztecAddress &contract_address, const FF &slot) const override
bool siloed_nullifier_exists(const FF &nullifier) const override
PublicDataTreeCheckInterface & public_data_tree_check
void storage_write(const AztecAddress &contract_address, const FF &slot, const FF &value, bool is_protocol_write) override
bool nullifier_exists_internal(std::optional< AztecAddress > contract_address, const FF &nullifier) const
void nullifier_write(const AztecAddress &contract_address, const FF &nullifier) override
L1ToL2MessageTreeCheckInterface & l1_to_l2_msg_tree_check
bool l1_to_l2_msg_exists(uint64_t leaf_index, const FF &msg_hash) const override
virtual AppendOnlyTreeSnapshot write(const FF &nullifier, std::optional< AztecAddress > contract_address, uint64_t nullifier_counter, const NullifierTreeLeafPreimage &low_leaf_preimage, uint64_t low_leaf_index, std::span< const FF > low_leaf_sibling_path, const AppendOnlyTreeSnapshot &prev_snapshot, std::optional< std::span< const FF > > insertion_sibling_path)=0
virtual void assert_read(const FF &nullifier, std::optional< AztecAddress > contract_address, bool exists, const NullifierTreeLeafPreimage &low_leaf_preimage, uint64_t low_leaf_index, std::span< const FF > sibling_path, const AppendOnlyTreeSnapshot &snapshot)=0
virtual 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)=0
virtual 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)=0
virtual bool contains(const AztecAddress &contract_address, const FF &slot)=0
virtual void insert(const AztecAddress &contract_address, const FF &slot)=0
std::string format(Args... args)
Definition log.hpp:21
::bb::crypto::merkle_tree::fr_sibling_path SiblingPath
Definition db.hpp:27
FF unconstrained_make_unique_note_hash(const FF &siloed_note_hash, const FF &first_nullifier, uint64_t note_hash_counter)
Definition merkle.cpp:41
::bb::crypto::merkle_tree::PublicDataLeafValue PublicDataLeafValue
Definition db.hpp:29
FF unconstrained_compute_leaf_slot(const AztecAddress &contract_address, const FF &slot)
Definition merkle.cpp:26
FF unconstrained_silo_note_hash(const AztecAddress &contract_address, const FF &note_hash)
Definition merkle.cpp:36
FF unconstrained_silo_nullifier(const AztecAddress &contract_address, const FF &nullifier)
Definition merkle.cpp:31
FF ContractClassId
std::optional< AztecAddress > get_derived_address(const ProtocolContracts &protocol_contracts, const AztecAddress &canonical_address)
bool is_protocol_contract_address(const AztecAddress &address)
AvmFlavorSettings::FF FF
Definition field.hpp:10
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
AppendOnlyTreeSnapshot noteHashTree
AppendOnlyTreeSnapshot nullifierTree
AppendOnlyTreeSnapshot l1ToL2MessageTree
AppendOnlyTreeSnapshot publicDataTree