Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
public_data_tree_trace.cpp
Go to the documentation of this file.
2
13
14// This tracegen file will generate both the public data check trace and the public data squash trace from the same
15// events. These two traces are sorted in a different order, so we need to process them separately.
16namespace bb::avm2::tracegen {
17
19using simulation::PublicDataTreeReadWriteEvent;
20
21namespace {
22
23struct EventWithDiscard {
24 simulation::PublicDataTreeReadWriteEvent event;
25 bool discard;
26};
27
28void process_public_data_tree_check_trace(const std::vector<EventWithDiscard>& events_with_metadata,
29 const std::unordered_map<FF, uint32_t>& first_write_per_slot,
30 const std::unordered_map<FF, FF>& last_value_per_slot,
31 TraceContainer& trace)
32{
33 using C = Column;
34
35 // This is a shifted trace, so we start at 1
36 uint32_t row = 1;
37
39
40 for (size_t i = 0; i < events_with_metadata.size(); i++) {
41 bool end = i == events_with_metadata.size() - 1;
42 const auto& event = events_with_metadata[i].event;
43 const bool discard = events_with_metadata[i].discard;
44
45 bool exists = event.low_leaf_preimage.leaf.slot == event.leaf_slot;
46 FF slot_low_leaf_slot_diff = event.leaf_slot - event.low_leaf_preimage.leaf.slot;
47
48 bool next_slot_is_nonzero = false;
49 FF next_slot = 0;
50 if (!exists) {
51 next_slot_is_nonzero = event.low_leaf_preimage.nextKey != 0;
52 next_slot = event.low_leaf_preimage.nextKey;
53 }
54
55 bool write = event.write_data.has_value();
56 // Note: the protocol_write and non_protocol_write are set by the MultiPermutationBuilder, but I also set them
57 // here for clarity/testing. Can remove, but would need to change the NegativeSetProtocolWrite test.
58 bool protocol_write = event.execution_id == std::numeric_limits<uint32_t>::max();
59 bool should_insert = !exists && write;
60 bool nondiscarded_write = write && !discard;
61 bool should_write_to_public_inputs =
62 nondiscarded_write && first_write_per_slot.at(event.leaf_slot) == event.execution_id;
63 FF final_value = nondiscarded_write ? last_value_per_slot.at(event.leaf_slot) : 0;
64
65 FF intermediate_root = 0;
67 FF updated_low_leaf_hash = 0;
68 FF new_leaf_hash = 0;
69 AppendOnlyTreeSnapshot next_snapshot = event.prev_snapshot;
70
71 if (write) {
72 next_snapshot = event.write_data->next_snapshot;
73 intermediate_root = event.write_data->intermediate_root;
74 updated_low_leaf = event.write_data->updated_low_leaf_preimage;
75 updated_low_leaf_hash = event.write_data->updated_low_leaf_hash;
76 new_leaf_hash = event.write_data->new_leaf_hash;
77 }
78 uint32_t clk = event.execution_id;
79 uint32_t clk_diff = end ? 0 : events_with_metadata[i + 1].event.execution_id - clk;
80
81 uint32_t public_data_writes_length = write_idx -
83 static_cast<uint32_t>(should_write_to_public_inputs);
84
85 trace.set(row,
86 { {
87 { C::public_data_check_sel, 1 },
88 { C::public_data_check_not_end, !end },
89 { C::public_data_check_end, end },
90 { C::public_data_check_value, event.value },
91 { C::public_data_check_slot, event.slot },
92 { C::public_data_check_root, event.prev_snapshot.root },
93 { C::public_data_check_address, event.contract_address },
94 { C::public_data_check_write_root, next_snapshot.root },
95 { C::public_data_check_tree_size_before_write, event.prev_snapshot.nextAvailableLeafIndex },
96 { C::public_data_check_tree_size_after_write, next_snapshot.nextAvailableLeafIndex },
97 { C::public_data_check_write, write },
98 { C::public_data_check_protocol_write, protocol_write },
99 { C::public_data_check_non_protocol_write, write && !protocol_write },
100 { C::public_data_check_clk, clk },
101 { C::public_data_check_discard, discard },
102 { C::public_data_check_low_leaf_slot, event.low_leaf_preimage.leaf.slot },
103 { C::public_data_check_low_leaf_value, event.low_leaf_preimage.leaf.value },
104 { C::public_data_check_low_leaf_next_index, event.low_leaf_preimage.nextIndex },
105 { C::public_data_check_low_leaf_next_slot, event.low_leaf_preimage.nextKey },
106 { C::public_data_check_updated_low_leaf_value, updated_low_leaf.leaf.value },
107 { C::public_data_check_updated_low_leaf_next_index, updated_low_leaf.nextIndex },
108 { C::public_data_check_updated_low_leaf_next_slot, updated_low_leaf.nextKey },
109 { C::public_data_check_low_leaf_index, event.low_leaf_index },
110 { C::public_data_check_clk_diff_lo, static_cast<uint16_t>(clk_diff) },
111 { C::public_data_check_clk_diff_hi, clk_diff >> 16 },
112 { C::public_data_check_leaf_slot, event.leaf_slot },
113 { C::public_data_check_siloing_separator, GENERATOR_INDEX__PUBLIC_LEAF_INDEX },
114 { C::public_data_check_leaf_not_exists, !exists },
115 { C::public_data_check_leaf_slot_low_leaf_slot_diff_inv,
116 slot_low_leaf_slot_diff }, // Will be inverted in batch later
117 { C::public_data_check_next_slot_is_nonzero, next_slot_is_nonzero },
118 { C::public_data_check_next_slot_inv, next_slot }, // Will be inverted in batch later
119 { C::public_data_check_low_leaf_hash, event.low_leaf_hash },
120 { C::public_data_check_intermediate_root, intermediate_root },
121 { C::public_data_check_tree_height, PUBLIC_DATA_TREE_HEIGHT },
122 { C::public_data_check_const_two, 2 },
123 { C::public_data_check_updated_low_leaf_hash, updated_low_leaf_hash },
124 { C::public_data_check_should_insert, should_insert },
125 { C::public_data_check_new_leaf_hash, new_leaf_hash },
126 { C::public_data_check_write_idx, write_idx },
127 { C::public_data_check_non_discarded_write, nondiscarded_write },
128 { C::public_data_check_should_write_to_public_inputs, should_write_to_public_inputs },
129 { C::public_data_check_final_value, final_value },
130 { C::public_data_check_public_data_writes_length, public_data_writes_length },
131 { C::public_data_check_length_pi_idx,
133 } });
134 row++;
135 if (should_write_to_public_inputs) {
136 write_idx++;
137 }
138 }
139}
140
141void process_squashing_trace(const std::vector<PublicDataTreeReadWriteEvent>& nondiscarded_writes,
142 const std::unordered_map<FF, uint32_t>& first_write_per_slot,
143 const std::unordered_map<FF, FF>& last_value_per_slot,
144 TraceContainer& trace)
145{
146 using C = Column;
147
148 // This is a shifted trace, so we start at 1
149 uint32_t row = 1;
150
151 for (size_t i = 0; i < nondiscarded_writes.size(); i++) {
152 bool end = i == nondiscarded_writes.size() - 1;
153 const auto& event = nondiscarded_writes[i];
154
155 uint32_t clk = event.execution_id;
156
157 bool leaf_slot_increase = false;
158 bool check_clock = false;
159 uint32_t clk_diff = 0;
160
161 if (!end) {
162 const auto& next_event = nondiscarded_writes[i + 1];
163
164 if (event.leaf_slot == next_event.leaf_slot) {
165 assert(event.execution_id < next_event.execution_id);
166 clk_diff = next_event.execution_id - event.execution_id;
167 check_clock = true;
168 } else {
169 assert(static_cast<uint256_t>(event.leaf_slot) < static_cast<uint256_t>(next_event.leaf_slot));
170 leaf_slot_increase = true;
171 }
172 }
173
174 bool should_write_to_public_inputs = first_write_per_slot.at(event.leaf_slot) == event.execution_id;
175 FF final_value = last_value_per_slot.at(event.leaf_slot);
176
177 trace.set(row,
178 { {
179 { C::public_data_squash_sel, 1 },
180 { C::public_data_squash_leaf_slot, event.leaf_slot },
181 { C::public_data_squash_value, event.value },
182 { C::public_data_squash_clk, clk },
183 { C::public_data_squash_write_to_public_inputs, should_write_to_public_inputs },
184 { C::public_data_squash_leaf_slot_increase, leaf_slot_increase },
185 { C::public_data_squash_check_clock, check_clock },
186 { C::public_data_squash_clk_diff_lo, static_cast<uint16_t>(clk_diff) },
187 { C::public_data_squash_clk_diff_hi, clk_diff >> 16 },
188 { C::public_data_squash_final_value, final_value },
189 } });
190 row++;
191 }
192}
193
194} // namespace
195
199{
200 std::vector<EventWithDiscard> events_with_metadata;
201 std::unordered_map<FF, uint32_t> first_write_per_slot;
202 std::unordered_map<FF, FF> last_value_per_slot;
203
204 events_with_metadata.reserve(events.size());
206 events_with_metadata.push_back({ event, discard });
207 if (!discard && event.write_data.has_value()) {
208 if (!first_write_per_slot.contains(event.leaf_slot)) {
209 first_write_per_slot[event.leaf_slot] = event.execution_id;
210 }
211 last_value_per_slot[event.leaf_slot] = event.value;
212 }
213 });
214
215 // Sort by clk in ascending order (reads will have clk=0)
216 std::ranges::sort(events_with_metadata.begin(),
217 events_with_metadata.end(),
218 [](const EventWithDiscard& a, const EventWithDiscard& b) {
219 return a.event.execution_id < b.event.execution_id;
220 });
221
222 process_public_data_tree_check_trace(events_with_metadata, first_write_per_slot, last_value_per_slot, trace);
223
225 nondiscarded_writes.reserve(events_with_metadata.size());
226 // Retain only nondiscarded writes
227 for (const auto& event_with_metadata : events_with_metadata) {
228 if (event_with_metadata.event.write_data.has_value() && !event_with_metadata.discard) {
229 nondiscarded_writes.push_back(event_with_metadata.event);
230 }
231 }
232
233 // Sort by slot, and then by clk
234 std::ranges::sort(nondiscarded_writes.begin(),
235 nondiscarded_writes.end(),
236 [](const PublicDataTreeReadWriteEvent& a, const PublicDataTreeReadWriteEvent& b) {
237 if (a.leaf_slot == b.leaf_slot) {
238 return a.execution_id < b.execution_id;
239 }
240 return static_cast<uint256_t>(a.leaf_slot) < static_cast<uint256_t>(b.leaf_slot);
241 });
242
243 process_squashing_trace(nondiscarded_writes, first_write_per_slot, last_value_per_slot, trace);
244
245 // Batch invert the columns.
247 { { Column::public_data_check_leaf_slot_low_leaf_slot_diff_inv, Column::public_data_check_next_slot_inv } });
248}
249
250const InteractionDefinition PublicDataTreeTraceBuilder::interactions =
251 InteractionDefinition()
252 // Public data read/write
253 .add<lookup_public_data_check_silo_poseidon2_settings, InteractionType::LookupGeneric>()
254 .add<lookup_public_data_check_low_leaf_slot_validation_settings, InteractionType::LookupGeneric>()
256 .add<lookup_public_data_check_low_leaf_poseidon2_0_settings, InteractionType::LookupGeneric>()
257 .add<lookup_public_data_check_low_leaf_poseidon2_1_settings, InteractionType::LookupGeneric>()
258 .add<lookup_public_data_check_updated_low_leaf_poseidon2_0_settings, InteractionType::LookupGeneric>()
260 .add<lookup_public_data_check_low_leaf_merkle_check_settings, InteractionType::LookupGeneric>()
261 .add<lookup_public_data_check_new_leaf_poseidon2_0_settings, InteractionType::LookupGeneric>()
262 .add<lookup_public_data_check_new_leaf_poseidon2_1_settings, InteractionType::LookupGeneric>()
263 .add<lookup_public_data_check_new_leaf_merkle_check_settings, InteractionType::LookupGeneric>()
264 .add<InteractionType::MultiPermutation, perm_sstore_storage_write_settings, perm_tx_balance_update_settings>(
265 Column::public_data_check_write)
266 .add<perm_public_data_check_squashing_settings, InteractionType::Permutation>()
268 InteractionType::LookupIntoIndexedByClk>()
269 .add<lookup_public_data_squash_leaf_slot_increase_ff_gt_settings, InteractionType::LookupGeneric>()
270 .add<lookup_public_data_squash_clk_diff_range_lo_settings, InteractionType::LookupIntoIndexedByClk>()
271 .add<lookup_public_data_squash_clk_diff_range_hi_settings, InteractionType::LookupIntoIndexedByClk>()
272 .add<lookup_public_data_check_clk_diff_range_lo_settings, InteractionType::LookupIntoIndexedByClk>()
273 .add<lookup_public_data_check_clk_diff_range_hi_settings, InteractionType::LookupIntoIndexedByClk>()
275 InteractionType::LookupIntoIndexedByClk>();
276
277} // namespace bb::avm2::tracegen
#define GENERATOR_INDEX__PUBLIC_LEAF_INDEX
#define AVM_PUBLIC_INPUTS_AVM_ACCUMULATED_DATA_ARRAY_LENGTHS_PUBLIC_DATA_WRITES_ROW_IDX
#define AVM_PUBLIC_INPUTS_AVM_ACCUMULATED_DATA_PUBLIC_DATA_WRITES_ROW_IDX
#define PUBLIC_DATA_TREE_HEIGHT
InteractionDefinition & add(auto &&... args)
void process(const simulation::EventEmitterInterface< simulation::PublicDataTreeCheckEvent >::Container &events, TraceContainer &trace)
void invert_columns(std::span< const Column > cols)
void set(Column col, uint32_t row, const FF &value)
TestTraceContainer trace
FF a
FF b
IndexedLeaf< PublicDataLeafValue > PublicDataTreeLeafPreimage
void process_with_discard(const std::vector< std::variant< EventType, simulation::CheckPointEventType > > &events, ProcessEventFn &&process_event)
permutation_settings< perm_public_data_check_squashing_settings_ > perm_public_data_check_squashing_settings
lookup_settings< lookup_public_data_check_low_leaf_next_slot_validation_settings_ > lookup_public_data_check_low_leaf_next_slot_validation_settings
lookup_settings< lookup_public_data_check_new_leaf_merkle_check_settings_ > lookup_public_data_check_new_leaf_merkle_check_settings
lookup_settings< lookup_public_data_check_updated_low_leaf_poseidon2_1_settings_ > lookup_public_data_check_updated_low_leaf_poseidon2_1_settings
lookup_settings< lookup_public_data_check_silo_poseidon2_settings_ > lookup_public_data_check_silo_poseidon2_settings
lookup_settings< lookup_public_data_check_write_writes_length_to_public_inputs_settings_ > lookup_public_data_check_write_writes_length_to_public_inputs_settings
lookup_settings< lookup_public_data_check_new_leaf_poseidon2_0_settings_ > lookup_public_data_check_new_leaf_poseidon2_0_settings
lookup_settings< lookup_public_data_squash_clk_diff_range_hi_settings_ > lookup_public_data_squash_clk_diff_range_hi_settings
lookup_settings< lookup_public_data_check_write_public_data_to_public_inputs_settings_ > lookup_public_data_check_write_public_data_to_public_inputs_settings
lookup_settings< lookup_public_data_check_low_leaf_poseidon2_1_settings_ > lookup_public_data_check_low_leaf_poseidon2_1_settings
lookup_settings< lookup_public_data_check_clk_diff_range_hi_settings_ > lookup_public_data_check_clk_diff_range_hi_settings
lookup_settings< lookup_public_data_squash_leaf_slot_increase_ff_gt_settings_ > lookup_public_data_squash_leaf_slot_increase_ff_gt_settings
void write(std::vector< uint8_t > &buf, ClientIVC::VerificationKey const &vk)
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
simulation::PublicDataTreeReadWriteEvent event
static IndexedLeaf< PublicDataLeafValue > empty()