Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
bytecode_trace.cpp
Go to the documentation of this file.
2
3#include <algorithm>
4#include <cstddef>
5#include <cstdint>
6#include <vector>
7
21
22namespace bb::avm2::tracegen {
23
25using C = Column;
26
42 TraceContainer& trace)
43{
44 // Since next_packed_pc - pc is always in the range [0, 31), we can precompute the inverses:
45 std::vector<FF> next_packed_pc_min_pc_inverses = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
46 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30 };
47 FF::batch_invert(next_packed_pc_min_pc_inverses);
48
49 // We start from row 1 because we need a row of zeroes for the shifts.
50 uint32_t row = 1;
51
52 for (const auto& event : events) {
53 const auto& bytecode = *event.bytecode;
54 const auto id = event.bytecode_id;
55 auto bytecode_at = [&bytecode](size_t i) -> uint8_t { return i < bytecode.size() ? bytecode[i] : 0; };
56 const uint32_t bytecode_len = static_cast<uint32_t>(bytecode.size());
57
58 for (uint32_t i = 0; i < bytecode_len; i++) {
59 const uint32_t remaining = bytecode_len - i;
60 const uint32_t bytes_to_read = std::min(remaining, DECOMPOSE_WINDOW_SIZE);
61 const bool is_last = remaining == 1;
62 const bool is_windows_eq_remaining = remaining == DECOMPOSE_WINDOW_SIZE;
63
64 // Check that we still expect the max public bytecode in bytes to fit within 24 bits (i.e. <= 0xffffff).
65 static_assert(MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS * 31 <= 0xffffff);
66
67 // We set the decomposition in bytes, and other values.
68 trace.set(row + i,
69 { {
70 { C::bc_decomposition_sel, 1 },
71 { C::bc_decomposition_id, id },
72 { C::bc_decomposition_pc, i },
73 { C::bc_decomposition_start, i == 0 ? 1 : 0 },
74 { C::bc_decomposition_last_of_contract, is_last ? 1 : 0 },
75 { C::bc_decomposition_bytes_remaining, remaining },
76 { C::bc_decomposition_bytes_to_read, bytes_to_read },
77 { C::bc_decomposition_sel_windows_gt_remaining, DECOMPOSE_WINDOW_SIZE > remaining ? 1 : 0 },
78 { C::bc_decomposition_sel_windows_eq_remaining, is_windows_eq_remaining ? 1 : 0 },
79 // Inverses will be calculated in batch later.
80 { C::bc_decomposition_bytes_rem_inv, remaining },
81 { C::bc_decomposition_bytes_rem_min_one_inv, is_last ? 0 : FF(remaining - 1) },
82 { C::bc_decomposition_windows_min_remaining_inv,
83 is_windows_eq_remaining ? 0 : FF(DECOMPOSE_WINDOW_SIZE) - FF(remaining) },
84 // Sliding window.
85 { C::bc_decomposition_bytes, bytecode_at(i) },
86 { C::bc_decomposition_bytes_pc_plus_1, bytecode_at(i + 1) },
87 { C::bc_decomposition_bytes_pc_plus_2, bytecode_at(i + 2) },
88 { C::bc_decomposition_bytes_pc_plus_3, bytecode_at(i + 3) },
89 { C::bc_decomposition_bytes_pc_plus_4, bytecode_at(i + 4) },
90 { C::bc_decomposition_bytes_pc_plus_5, bytecode_at(i + 5) },
91 { C::bc_decomposition_bytes_pc_plus_6, bytecode_at(i + 6) },
92 { C::bc_decomposition_bytes_pc_plus_7, bytecode_at(i + 7) },
93 { C::bc_decomposition_bytes_pc_plus_8, bytecode_at(i + 8) },
94 { C::bc_decomposition_bytes_pc_plus_9, bytecode_at(i + 9) },
95 { C::bc_decomposition_bytes_pc_plus_10, bytecode_at(i + 10) },
96 { C::bc_decomposition_bytes_pc_plus_11, bytecode_at(i + 11) },
97 { C::bc_decomposition_bytes_pc_plus_12, bytecode_at(i + 12) },
98 { C::bc_decomposition_bytes_pc_plus_13, bytecode_at(i + 13) },
99 { C::bc_decomposition_bytes_pc_plus_14, bytecode_at(i + 14) },
100 { C::bc_decomposition_bytes_pc_plus_15, bytecode_at(i + 15) },
101 { C::bc_decomposition_bytes_pc_plus_16, bytecode_at(i + 16) },
102 { C::bc_decomposition_bytes_pc_plus_17, bytecode_at(i + 17) },
103 { C::bc_decomposition_bytes_pc_plus_18, bytecode_at(i + 18) },
104 { C::bc_decomposition_bytes_pc_plus_19, bytecode_at(i + 19) },
105 { C::bc_decomposition_bytes_pc_plus_20, bytecode_at(i + 20) },
106 { C::bc_decomposition_bytes_pc_plus_21, bytecode_at(i + 21) },
107 { C::bc_decomposition_bytes_pc_plus_22, bytecode_at(i + 22) },
108 { C::bc_decomposition_bytes_pc_plus_23, bytecode_at(i + 23) },
109 { C::bc_decomposition_bytes_pc_plus_24, bytecode_at(i + 24) },
110 { C::bc_decomposition_bytes_pc_plus_25, bytecode_at(i + 25) },
111 { C::bc_decomposition_bytes_pc_plus_26, bytecode_at(i + 26) },
112 { C::bc_decomposition_bytes_pc_plus_27, bytecode_at(i + 27) },
113 { C::bc_decomposition_bytes_pc_plus_28, bytecode_at(i + 28) },
114 { C::bc_decomposition_bytes_pc_plus_29, bytecode_at(i + 29) },
115 { C::bc_decomposition_bytes_pc_plus_30, bytecode_at(i + 30) },
116 { C::bc_decomposition_bytes_pc_plus_31, bytecode_at(i + 31) },
117 { C::bc_decomposition_bytes_pc_plus_32, bytecode_at(i + 32) },
118 { C::bc_decomposition_bytes_pc_plus_33, bytecode_at(i + 33) },
119 { C::bc_decomposition_bytes_pc_plus_34, bytecode_at(i + 34) },
120 { C::bc_decomposition_bytes_pc_plus_35, bytecode_at(i + 35) },
121 { C::bc_decomposition_bytes_pc_plus_36, bytecode_at(i + 36) },
122 } });
123 }
124
125 // We set the packed field every 31 bytes.
126 auto bytecode_field_at = [&](size_t i) -> FF {
127 // We need to read uint256_ts because reading FFs messes up the order of the bytes.
128 uint256_t as_int = 0;
129 if (bytecode_len - i >= 32) {
130 // If we have more than 31 bytes remaining, we read 32 bytes directly from the bytecode
131 // vector starting at byte i:
132 as_int = from_buffer<uint256_t>(bytecode, i);
133 } else {
134 // Otherwise, we pad the final bytes with zeros to 32:
135 std::vector<uint8_t> tail(bytecode.begin() + static_cast<ssize_t>(i), bytecode.end());
136 tail.resize(32, 0);
137 as_int = from_buffer<uint256_t>(tail, 0);
138 }
139 // We shift to form a 31 byte int:
140 return as_int >> 8;
141 };
142 for (uint32_t i = 0; i < bytecode_len; i += 31) {
143 // Set the packed field and related columns. Note that the multipermutation columns (sel_packed_read)
144 // are set separately by the MultiPermutationBuilder.
145 trace.set(row + i,
146 { {
147 { C::bc_decomposition_sel_packed, 1 },
148 { C::bc_decomposition_packed_field, bytecode_field_at(i) },
149 { C::bc_decomposition_next_packed_pc, i },
150 { C::bc_decomposition_next_packed_pc_min_pc_inv, 0 },
151 } });
152 // At each row until the next packed field, set the next pc and inverse required for the zero check
153 // (#[PC_IS_PACKED]):
154 for (uint32_t j = i + 1; j < std::min(bytecode_len, i + 31); j++) {
155 trace.set(
156 row + j,
157 { {
158 { C::bc_decomposition_next_packed_pc, i + 31 },
159 { C::bc_decomposition_next_packed_pc_min_pc_inv, next_packed_pc_min_pc_inverses[i + 31 - j] },
160 } });
161 }
162 }
163
164 // We advance to the next bytecode.
165 row += bytecode_len;
166 }
167
168 // Batch invert the columns.
169 trace.invert_columns({ { C::bc_decomposition_bytes_rem_inv,
170 C::bc_decomposition_bytes_rem_min_one_inv,
171 C::bc_decomposition_windows_min_remaining_inv } });
172}
173
188{
189 // bc_hashing.pil uses some shifted columns and therefore we start from row 1.
190 uint32_t row = 1;
191
192 for (const auto& event : events) {
193 // Note that bytecode fields from the BytecodeHashingEvent do not contain the prepended field length | separator
194
195 const auto& id = event.bytecode_id;
196 const auto input_len = event.bytecode_fields.size() + 1; // +1 for the prepended field length | separator
197 const auto padding_amount = (3 - (input_len % 3)) % 3;
198
199 std::vector<FF> fields = { simulation::compute_public_bytecode_first_field(event.bytecode_length_in_bytes) };
200 fields.reserve(input_len + padding_amount);
201 fields.insert(fields.end(), event.bytecode_fields.begin(), event.bytecode_fields.end());
202 fields.insert(fields.end(), padding_amount, FF(0)); // Add padding fields.
203
204 const auto num_rounds = fields.size() / 3;
205
206 for (size_t i = 0; i < num_rounds; i++) {
207 bool start_of_bytecode = i == 0;
208 bool end_of_bytecode = i == num_rounds - 1;
209 // When we start the bytecode, we want to look up field 1 at pc = 0 in the decomposition trace, since we
210 // force field 0 to be the separator.
211 // Layout is: PC_INDEX, PC_INDEX_1, PC_INDEX_2
212 // 0 0 31
213 // 62 93 124
214 uint32_t pc_index_1 = 93 * static_cast<uint32_t>(i);
215 uint32_t pc_index = i > 0 ? pc_index_1 - 31 : 0;
216 trace.set(row,
217 { { { C::bc_hashing_sel, 1 },
218 { C::bc_hashing_start, start_of_bytecode ? 1 : 0 },
219 { C::bc_hashing_sel_not_start, !start_of_bytecode ? 1 : 0 },
220 { C::bc_hashing_end, end_of_bytecode ? 1 : 0 },
221 { C::bc_hashing_bytecode_id, id },
222 { C::bc_hashing_size_in_bytes,
223 event.bytecode_length_in_bytes }, // Note: only needs to be constrained at start
224 { C::bc_hashing_input_len, input_len },
225 { C::bc_hashing_rounds_rem, num_rounds - i },
226 { C::bc_hashing_pc_index, pc_index },
227 { C::bc_hashing_pc_index_1, pc_index_1 },
228 { C::bc_hashing_pc_index_2, pc_index_1 + 31 },
229 { C::bc_hashing_packed_fields_0, fields[i * 3] },
230 { C::bc_hashing_packed_fields_1, fields[(i * 3) + 1] },
231 { C::bc_hashing_packed_fields_2, fields[(i * 3) + 2] },
232 { C::bc_hashing_sel_not_padding_1, end_of_bytecode && padding_amount == 2 ? 0 : 1 },
233 { C::bc_hashing_sel_not_padding_2, end_of_bytecode && padding_amount > 0 ? 0 : 1 },
234 { C::bc_hashing_padding, padding_amount } } });
235 row++;
236 }
237 }
238}
239
255 TraceContainer& trace)
256{
257 uint32_t row = 0;
258 for (const auto& event : events) {
259 // Since the maximum is (currently) 21 and we prove incrementation of next_available_leaf_index
260 // at each row, the use of uint64 should be safe and never underflow.
261 uint64_t remaining_bytecodes = MAX_PUBLIC_CALLS_TO_UNIQUE_CONTRACT_CLASS_IDS +
263 event.retrieved_bytecodes_snapshot_before.next_available_leaf_index;
264 bool error = event.error.has_value();
266 BB_ASSERT(event.is_new_class == true & remaining_bytecodes == 0,
267 "TOO_MANY_BYTECODES error incorrectly set for bytecode retrieval");
268 }
269 trace.set(
270 row,
271 { {
272 { C::bc_retrieval_sel, 1 },
273 { C::bc_retrieval_bytecode_id, event.bytecode_id },
274 { C::bc_retrieval_address, event.address },
275
276 // Contract instance members (for lookup into contract_instance_retrieval)
277 { C::bc_retrieval_current_class_id, event.current_class_id },
278
279 // Contract class members (for lookup into class_id_derivation)
280 { C::bc_retrieval_artifact_hash, event.contract_class.artifact_hash },
281 { C::bc_retrieval_private_functions_root, event.contract_class.private_functions_root },
282
283 // Tree context (for lookup into contract_instance_retrieval)
284 { C::bc_retrieval_public_data_tree_root, event.public_data_tree_root },
285 { C::bc_retrieval_nullifier_tree_root, event.nullifier_tree_root },
286
287 // Retrieved bytecodes tree context (for lookup into indexed_tree_check)
288 { C::bc_retrieval_retrieved_bytecodes_tree_height, AVM_RETRIEVED_BYTECODES_TREE_HEIGHT },
289 { C::bc_retrieval_retrieved_bytecodes_merkle_separator, DOM_SEP__RETRIEVED_BYTECODES_MERKLE },
290 { C::bc_retrieval_prev_retrieved_bytecodes_tree_root, event.retrieved_bytecodes_snapshot_before.root },
291 { C::bc_retrieval_prev_retrieved_bytecodes_tree_size,
292 event.retrieved_bytecodes_snapshot_before.next_available_leaf_index },
293 { C::bc_retrieval_next_retrieved_bytecodes_tree_root, event.retrieved_bytecodes_snapshot_after.root },
294 { C::bc_retrieval_next_retrieved_bytecodes_tree_size,
295 event.retrieved_bytecodes_snapshot_after.next_available_leaf_index },
296
297 // Instance existence determined by shared contract instance retrieval
298 { C::bc_retrieval_instance_exists,
300
301 // Error handling
302 { C::bc_retrieval_error, error ? 1 : 0 },
303 { C::bc_retrieval_is_new_class, event.is_new_class },
304 { C::bc_retrieval_should_retrieve, error ? 0 : 1 },
305 // Too many bytecodes handling
306 { C::bc_retrieval_no_remaining_bytecodes, remaining_bytecodes == 0 ? 1 : 0 },
307 { C::bc_retrieval_remaining_bytecodes_inv, remaining_bytecodes }, // Will be inverted in batch later.
308 } });
309 row++;
310 }
311
312 // Batch invert the columns.
313 trace.invert_columns({ { C::bc_retrieval_remaining_bytecodes_inv } });
314}
315
338 TraceContainer& trace)
339{
345
346 uint32_t row = 0;
347
348 for (const auto& event : events) {
349 const auto bytecode_size = event.bytecode->size();
350 // To match column PARSING_ERROR_EXCEPT_TAG_ERROR:
351 const bool parsing_error_non_tag = event.error == PC_OUT_OF_RANGE || event.error == OPCODE_OUT_OF_RANGE ||
352 event.error == INSTRUCTION_OUT_OF_RANGE;
353
354 // Operands are constrained to be 0 in the circuit when PARSING_ERROR_EXCEPT_TAG_ERROR:
355 auto get_operand = [&](size_t i) -> FF {
356 return i < event.instruction.operands.size() && !parsing_error_non_tag
357 ? static_cast<FF>(event.instruction.operands[i])
358 : 0;
359 };
360 auto bytecode_at = [&](size_t i) -> uint8_t { return i < bytecode_size ? (*event.bytecode)[i] : 0; };
361
362 // To match column bd0, the first byte of the instruction which holds the wire opcode.
363 const uint8_t wire_opcode = bytecode_at(event.pc);
364 // Corresponds to !opcode_out_of_range (PC_OUT_OF_RANGE is checked first since we have error disjointedness).
365 const bool wire_opcode_in_range = event.error != PC_OUT_OF_RANGE && event.error != OPCODE_OUT_OF_RANGE;
366
367 // To match corresponding columns (initialized as 0 to match circuit behaviour in error cases):
368 // - PC_OUT_OF_RANGE: The below remain 0 (matching sel_pc_in_range == 0 and PARSING_ERROR_EXCEPT_TAG_ERROR
369 // circuit logic) as there is nothing to read from the bytecode.
370 // - OPCODE_OUT_OF_RANGE: The below remain 0 since we do not have a valid opcode. This matches the
371 // #[WIRE_INSTRUCTION_INFO] lookup where opcode_out_of_range == 1 implies all other
372 // tuple fields are 0.
373 // - INSTRUCTION_OUT_OF_RANGE: The below are assigned according to the wire opcode and instr_size is used to
374 // constrain the instr_out_of_range flag. Note that operands are forced to be 0
375 // (correctly matching PARSING_ERROR_EXCEPT_TAG_ERROR circuit logic) meaning
376 // tag_value can only be 0. This is fine as #[TAG_VALUE_VALIDATION] passes for 0
377 // trivially and the circuit still enforces sel_parsing_err == 1.
378 // - TAG_OUT_OF_RANGE: The below, including operands, are all assigned, matching circuit behaviour for
379 // PARSING_ERROR_EXCEPT_TAG_ERROR == 0.
380 uint32_t instr_size = 0;
381 ExecutionOpCode exec_opcode = static_cast<ExecutionOpCode>(0);
382 std::array<uint8_t, NUM_OP_DC_SELECTORS> op_dc_selectors{};
383 bool has_tag = false;
384 bool tag_is_op2 = false;
385 uint8_t tag_value = 0;
386
387 if (wire_opcode_in_range) {
388 const auto& wire_instr_spec = get_wire_instruction_spec().at(static_cast<WireOpCode>(wire_opcode));
389 instr_size = wire_instr_spec.size_in_bytes;
390 exec_opcode = wire_instr_spec.exec_opcode;
391 op_dc_selectors = wire_instr_spec.op_dc_selectors;
392
393 if (wire_instr_spec.tag_operand_idx.has_value()) {
394 const auto tag_value_idx = wire_instr_spec.tag_operand_idx.value();
395 BB_ASSERT((tag_value_idx == 2 || tag_value_idx == 3),
396 "Current constraints support only tag for operand index equal to 2 or 3");
397 has_tag = true;
398 tag_value =
399 static_cast<uint8_t>(get_operand(tag_value_idx - 1)); // op2/op3 live at instruction.operands[1/2]
400 tag_is_op2 = tag_value_idx == 2;
401 }
402 }
403
404 uint32_t bytecode_size_u32 = static_cast<uint32_t>(bytecode_size);
405 uint32_t pc_abs_diff =
406 event.error == PC_OUT_OF_RANGE ? event.pc - bytecode_size_u32 : bytecode_size_u32 - event.pc - 1;
407
408 // If OPCODE_OUT_OF_RANGE, we still have valid bytecode to read, but have no
409 // instruction and hence instr_size = 0. This matches the expected table entry for
410 // opcode_out_of_range == 1 (#[WIRE_INSTRUCTION_INFO]) and the diff check passes
411 // for instr_abs_diff = bytes_to_read:
412 const uint32_t bytes_remaining = event.error == PC_OUT_OF_RANGE ? 0 : bytecode_size_u32 - event.pc;
413 const uint32_t bytes_to_read = std::min(bytes_remaining, DECOMPOSE_WINDOW_SIZE);
414 uint32_t instr_abs_diff =
415 event.error == INSTRUCTION_OUT_OF_RANGE ? instr_size - bytes_to_read - 1 : bytes_to_read - instr_size;
416
417 trace.set(row,
418 { {
419 { C::instr_fetching_sel, 1 },
420 // Unique pair defining the instruction.
421 { C::instr_fetching_pc, event.pc },
422 { C::instr_fetching_bytecode_id, event.bytecode_id },
423
424 // Parsing error flags.
425 { C::instr_fetching_pc_out_of_range, event.error == PC_OUT_OF_RANGE ? 1 : 0 },
426 { C::instr_fetching_opcode_out_of_range, event.error == OPCODE_OUT_OF_RANGE ? 1 : 0 },
427 { C::instr_fetching_instr_out_of_range, event.error == INSTRUCTION_OUT_OF_RANGE ? 1 : 0 },
428 { C::instr_fetching_tag_out_of_range, event.error == TAG_OUT_OF_RANGE ? 1 : 0 },
429 { C::instr_fetching_sel_parsing_err, event.error.has_value() ? 1 : 0 },
430 { C::instr_fetching_sel_pc_in_range, event.error != PC_OUT_OF_RANGE ? 1 : 0 },
431
432 // Error handling.
433 { C::instr_fetching_bytecode_size, bytecode_size },
434 { C::instr_fetching_bytes_to_read, bytes_to_read },
435 { C::instr_fetching_instr_size, instr_size },
436 { C::instr_fetching_instr_abs_diff, instr_abs_diff },
437 { C::instr_fetching_pc_abs_diff, pc_abs_diff },
438 // Constant column (this is temp because aliasing is not allowed in lookups).
439 { C::instr_fetching_pc_size_in_bits, AVM_PC_SIZE_IN_BITS },
440
441 // Tag metadata.
442 { C::instr_fetching_tag_value, tag_value },
443 { C::instr_fetching_sel_has_tag, has_tag ? 1 : 0 },
444 { C::instr_fetching_sel_tag_is_op2, tag_is_op2 ? 1 : 0 },
445
446 // Execution opcode.
447 { C::instr_fetching_exec_opcode, static_cast<uint32_t>(exec_opcode) },
448
449 // Addressing mode and operands.
450 { C::instr_fetching_addressing_mode, event.instruction.addressing_mode },
451 { C::instr_fetching_op1, get_operand(0) },
452 { C::instr_fetching_op2, get_operand(1) },
453 { C::instr_fetching_op3, get_operand(2) },
454 { C::instr_fetching_op4, get_operand(3) },
455 { C::instr_fetching_op5, get_operand(4) },
456 { C::instr_fetching_op6, get_operand(5) },
457 { C::instr_fetching_op7, get_operand(6) },
458
459 // Single instruction bytes.
460 { C::instr_fetching_bd0, wire_opcode },
461 { C::instr_fetching_bd1, bytecode_at(event.pc + 1) },
462 { C::instr_fetching_bd2, bytecode_at(event.pc + 2) },
463 { C::instr_fetching_bd3, bytecode_at(event.pc + 3) },
464 { C::instr_fetching_bd4, bytecode_at(event.pc + 4) },
465 { C::instr_fetching_bd5, bytecode_at(event.pc + 5) },
466 { C::instr_fetching_bd6, bytecode_at(event.pc + 6) },
467 { C::instr_fetching_bd7, bytecode_at(event.pc + 7) },
468 { C::instr_fetching_bd8, bytecode_at(event.pc + 8) },
469 { C::instr_fetching_bd9, bytecode_at(event.pc + 9) },
470 { C::instr_fetching_bd10, bytecode_at(event.pc + 10) },
471 { C::instr_fetching_bd11, bytecode_at(event.pc + 11) },
472 { C::instr_fetching_bd12, bytecode_at(event.pc + 12) },
473 { C::instr_fetching_bd13, bytecode_at(event.pc + 13) },
474 { C::instr_fetching_bd14, bytecode_at(event.pc + 14) },
475 { C::instr_fetching_bd15, bytecode_at(event.pc + 15) },
476 { C::instr_fetching_bd16, bytecode_at(event.pc + 16) },
477 { C::instr_fetching_bd17, bytecode_at(event.pc + 17) },
478 { C::instr_fetching_bd18, bytecode_at(event.pc + 18) },
479 { C::instr_fetching_bd19, bytecode_at(event.pc + 19) },
480 { C::instr_fetching_bd20, bytecode_at(event.pc + 20) },
481 { C::instr_fetching_bd21, bytecode_at(event.pc + 21) },
482 { C::instr_fetching_bd22, bytecode_at(event.pc + 22) },
483 { C::instr_fetching_bd23, bytecode_at(event.pc + 23) },
484 { C::instr_fetching_bd24, bytecode_at(event.pc + 24) },
485 { C::instr_fetching_bd25, bytecode_at(event.pc + 25) },
486 { C::instr_fetching_bd26, bytecode_at(event.pc + 26) },
487 { C::instr_fetching_bd27, bytecode_at(event.pc + 27) },
488 { C::instr_fetching_bd28, bytecode_at(event.pc + 28) },
489 { C::instr_fetching_bd29, bytecode_at(event.pc + 29) },
490 { C::instr_fetching_bd30, bytecode_at(event.pc + 30) },
491 { C::instr_fetching_bd31, bytecode_at(event.pc + 31) },
492 { C::instr_fetching_bd32, bytecode_at(event.pc + 32) },
493 { C::instr_fetching_bd33, bytecode_at(event.pc + 33) },
494 { C::instr_fetching_bd34, bytecode_at(event.pc + 34) },
495 { C::instr_fetching_bd35, bytecode_at(event.pc + 35) },
496 { C::instr_fetching_bd36, bytecode_at(event.pc + 36) },
497
498 // Operand decomposition selectors.
499 { C::instr_fetching_sel_op_dc_0, op_dc_selectors.at(0) },
500 { C::instr_fetching_sel_op_dc_1, op_dc_selectors.at(1) },
501 { C::instr_fetching_sel_op_dc_2, op_dc_selectors.at(2) },
502 { C::instr_fetching_sel_op_dc_3, op_dc_selectors.at(3) },
503 { C::instr_fetching_sel_op_dc_4, op_dc_selectors.at(4) },
504 { C::instr_fetching_sel_op_dc_5, op_dc_selectors.at(5) },
505 { C::instr_fetching_sel_op_dc_6, op_dc_selectors.at(6) },
506 { C::instr_fetching_sel_op_dc_7, op_dc_selectors.at(7) },
507 { C::instr_fetching_sel_op_dc_8, op_dc_selectors.at(8) },
508 { C::instr_fetching_sel_op_dc_9, op_dc_selectors.at(9) },
509 { C::instr_fetching_sel_op_dc_10, op_dc_selectors.at(10) },
510 { C::instr_fetching_sel_op_dc_11, op_dc_selectors.at(11) },
511 { C::instr_fetching_sel_op_dc_12, op_dc_selectors.at(12) },
512 { C::instr_fetching_sel_op_dc_13, op_dc_selectors.at(13) },
513 { C::instr_fetching_sel_op_dc_14, op_dc_selectors.at(14) },
514 { C::instr_fetching_sel_op_dc_15, op_dc_selectors.at(15) },
515 { C::instr_fetching_sel_op_dc_16, op_dc_selectors.at(16) },
516 } });
517 row++;
518 }
519}
520
523 // Bytecode Hashing
528 perm_bc_hashing_get_packed_field_2_settings>(C::bc_decomposition_sel_packed)
530 // Bytecode Retrieval
531 .add<InteractionType::LookupSequential, lookup_bc_retrieval_contract_instance_retrieval_settings>()
533 .add<InteractionType::LookupSequential, lookup_bc_retrieval_is_new_class_check_settings>()
535 // Bytecode Decomposition
536 .add<InteractionType::LookupIntoIndexedByRow, lookup_bc_decomposition_bytes_are_bytes_settings>()
537 // Instruction Fetching
539 .add<InteractionType::LookupIntoIndexedByRow, lookup_instr_fetching_instr_abs_diff_positive_settings>()
541 // The lookups into bc_decomposition cannnot be sequential because we deduplicate instruction
542 // fetches. Additionally the instruction rows are not necessarily ordered by bytecode position.
543 .add<InteractionType::LookupGeneric, lookup_instr_fetching_bytecode_size_from_bc_dec_settings>()
545 .add<InteractionType::LookupIntoIndexedByRow, lookup_instr_fetching_wire_instruction_info_settings>();
546
547} // namespace bb::avm2::tracegen
#define BB_ASSERT(expression,...)
Definition assert.hpp:70
std::shared_ptr< Napi::ThreadSafeFunction > bytecode
#define AVM_RETRIEVED_BYTECODES_TREE_INITIAL_SIZE
#define MAX_PUBLIC_CALLS_TO_UNIQUE_CONTRACT_CLASS_IDS
#define AVM_PC_SIZE_IN_BITS
#define MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS
#define AVM_RETRIEVED_BYTECODES_TREE_HEIGHT
#define DOM_SEP__RETRIEVED_BYTECODES_MERKLE
void process_retrieval(const simulation::EventEmitterInterface< simulation::BytecodeRetrievalEvent >::Container &events, TraceContainer &trace)
Process bytecode retrieval events and populate the relevant columns in the trace. Corresponds to bc_r...
static const InteractionDefinition interactions
void process_decomposition(const simulation::EventEmitterInterface< simulation::BytecodeDecompositionEvent >::Container &events, TraceContainer &trace)
Process bytecode decomposition events and populate the relevant columns in the trace....
void process_hashing(const simulation::EventEmitterInterface< simulation::BytecodeHashingEvent >::Container &events, TraceContainer &trace)
Process bytecode hashing events and populate the bc_hashing columns in the trace. Corresponds to bc_h...
void process_instruction_fetching(const simulation::EventEmitterInterface< simulation::InstructionFetchingEvent >::Container &events, TraceContainer &trace)
Process instruction fetching events and populate the relevant columns in the trace....
InteractionDefinition & add(auto &&... args)
Native Poseidon2 hash function implementation.
Definition poseidon2.hpp:22
TestTraceContainer trace
FF compute_public_bytecode_first_field(size_t bytecode_size)
AvmFlavorSettings::FF FF
Definition field.hpp:10
const std::unordered_map< WireOpCode, WireInstructionSpec > & get_wire_instruction_spec()
constexpr uint32_t DECOMPOSE_WINDOW_SIZE
simulation::PublicDataTreeReadWriteEvent event
Settings to be passed ot GenericLookupRelationImpl.
std::shared_ptr< std::vector< uint8_t > > bytecode
static void batch_invert(C &coeffs) noexcept
Batch invert a collection of field elements using Montgomery's trick.