Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
precomputed_trace.cpp
Go to the documentation of this file.
2
3#include <array>
4#include <cstdint>
5#include <vector>
6
19
20namespace bb::avm2::tracegen {
21
22using C = Column;
23
30void PrecomputedTraceBuilder::process_misc(TraceContainer& trace, const uint32_t num_rows)
31{
32 // First row.
33 trace.set(C::precomputed_first_row, 0, 1);
34
35 // Note: precomputed_zero is intentionally not populated.
36 // The trace container defaults unset values to FF(0), which is the desired value.
37
38 // Idx
39 trace.reserve_column(C::precomputed_idx, num_rows);
40 for (uint32_t i = 0; i < num_rows; i++) {
41 trace.set(C::precomputed_idx, i, i);
42 }
43}
44
51{
52 // 256 per input (a and b), and 3 different bitwise ops
53 constexpr auto num_rows = 256 * 256;
54 static_assert(num_rows <= PRECOMPUTED_TRACE_SIZE);
55 trace.reserve_column(C::precomputed_bitwise_input_a, num_rows);
56 trace.reserve_column(C::precomputed_bitwise_input_b, num_rows);
57 trace.reserve_column(C::precomputed_bitwise_output_and, num_rows);
58 trace.reserve_column(C::precomputed_bitwise_output_or, num_rows);
59 trace.reserve_column(C::precomputed_bitwise_output_xor, num_rows);
60
61 // row # is derived as:
62 // - input_b: bits 0...7 (0 being LSB)
63 // - input_a: bits 8...15
64 for (uint32_t a = 0; a < 256; a++) {
65 for (uint32_t b = 0; b < 256; b++) {
66 trace.set((a << 8) | b,
67 { {
68 { C::precomputed_bitwise_input_a, FF(a) },
69 { C::precomputed_bitwise_input_b, FF(b) },
70 { C::precomputed_bitwise_output_and, FF(a & b) },
71 { C::precomputed_bitwise_output_or, FF(a | b) },
72 { C::precomputed_bitwise_output_xor, FF(a ^ b) },
73 } });
74 }
75 }
76}
77
84{
85 constexpr auto num_rows = 1 << 8; // 256
86 // Set this selector high for the first 2^8 rows
87 // For these rows, idx will be 0...255
88 trace.reserve_column(C::precomputed_sel_range_8, num_rows);
89 for (uint32_t i = 0; i < num_rows; i++) {
90 trace.set(C::precomputed_sel_range_8, i, 1);
91 }
92}
93
100{
101 constexpr auto num_rows = 1 << 16; // 2^16
102 // Set this selector high for the first 2^16 rows
103 // For these rows, idx will be 0...2^16-1
104 trace.reserve_column(C::precomputed_sel_range_16, num_rows);
105 for (uint32_t i = 0; i < num_rows; i++) {
106 trace.set(C::precomputed_sel_range_16, i, 1);
107 }
108}
109
115{
116 // This corresponds to the fact that sel_range_8 is used as the dst selector for lookups involving powers of 2.
117 constexpr auto num_rows = 1 << 8; // 2^8 = 256
118 trace.reserve_column(C::precomputed_power_of_2, num_rows);
119 for (uint32_t i = 0; i < num_rows; i++) {
120 trace.set(C::precomputed_power_of_2, i, uint256_t(1) << uint256_t(i));
121 }
122}
123
129{
130 constexpr std::array<uint32_t, 64> round_constants{
131 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
132 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
133 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
134 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
135 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
136 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
137 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
138 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
139 };
140 constexpr auto num_rows = round_constants.size();
141 trace.reserve_column(C::precomputed_sha256_compression_round_constant, num_rows);
142 trace.reserve_column(C::precomputed_sel_sha256_compression, num_rows);
143 for (uint32_t i = 0; i < num_rows; i++) {
144 trace.set(i,
145 { { { C::precomputed_sel_sha256_compression, 1 },
146 { C::precomputed_sha256_compression_round_constant, round_constants[i] } } });
147 }
148}
149
155{
157
158 constexpr uint32_t NUM_TAGS = static_cast<uint32_t>(MemoryTag::MAX) + 1;
159 for (uint32_t i = 0; i < NUM_TAGS; i++) {
160 const auto tag = static_cast<MemoryTag>(i);
161 trace.set(i, // Column number corresponds to MemoryTag enum value.
162 { {
163 { C::precomputed_sel_tag_parameters, 1 },
164 { C::precomputed_tag_byte_length, get_tag_bytes(tag) },
165 { C::precomputed_tag_max_bits, get_tag_bits(tag) },
166 { C::precomputed_tag_max_value, get_tag_max_value(tag) },
167 } });
168 }
169}
170
179{
180 const std::array<Column, NUM_OP_DC_SELECTORS> sel_op_dc_columns = {
181 C::precomputed_sel_op_dc_0, C::precomputed_sel_op_dc_1, C::precomputed_sel_op_dc_2,
182 C::precomputed_sel_op_dc_3, C::precomputed_sel_op_dc_4, C::precomputed_sel_op_dc_5,
183 C::precomputed_sel_op_dc_6, C::precomputed_sel_op_dc_7, C::precomputed_sel_op_dc_8,
184 C::precomputed_sel_op_dc_9, C::precomputed_sel_op_dc_10, C::precomputed_sel_op_dc_11,
185 C::precomputed_sel_op_dc_12, C::precomputed_sel_op_dc_13, C::precomputed_sel_op_dc_14,
186 C::precomputed_sel_op_dc_15, C::precomputed_sel_op_dc_16,
187 };
188
189 // First set the selector for this table lookup.
190 constexpr uint32_t num_rows = 1 << 8; // 256
191 constexpr uint32_t num_opcodes = static_cast<uint32_t>(WireOpCode::LAST_OPCODE_SENTINEL);
192 trace.reserve_column(C::precomputed_opcode_out_of_range, num_rows - num_opcodes);
193 for (uint32_t i = num_opcodes; i < num_rows; i++) {
194 trace.set(C::precomputed_opcode_out_of_range, i, 1);
195 }
196
197 for (size_t i = 0; i < NUM_OP_DC_SELECTORS; i++) {
198 trace.reserve_column(sel_op_dc_columns.at(i), num_opcodes);
199 }
200 trace.reserve_column(C::precomputed_exec_opcode, num_opcodes);
201 trace.reserve_column(C::precomputed_instr_size, num_opcodes);
202
203 // Fill the lookup tables with the operand decomposition selectors.
204 for (const auto& [wire_opcode, wire_instruction_spec] : get_wire_instruction_spec()) {
205 for (size_t i = 0; i < NUM_OP_DC_SELECTORS; i++) {
206 trace.set(sel_op_dc_columns.at(i),
207 static_cast<uint32_t>(wire_opcode),
208 wire_instruction_spec.op_dc_selectors.at(i));
209 }
210 trace.set(C::precomputed_exec_opcode,
211 static_cast<uint32_t>(wire_opcode),
212 static_cast<uint32_t>(wire_instruction_spec.exec_opcode));
213 trace.set(C::precomputed_instr_size, static_cast<uint32_t>(wire_opcode), wire_instruction_spec.size_in_bytes);
214
215 if (wire_instruction_spec.tag_operand_idx.has_value()) {
216 trace.set(C::precomputed_sel_has_tag, static_cast<uint32_t>(wire_opcode), 1);
217
218 if (wire_instruction_spec.tag_operand_idx.value() == 2) {
219 trace.set(C::precomputed_sel_tag_is_op2, static_cast<uint32_t>(wire_opcode), 1);
220 }
221 }
222 }
223}
224
233{
234 constexpr std::array<Column, AVM_MAX_REGISTERS> MEM_OP_REG_COLUMNS = {
235 Column::precomputed_sel_mem_op_reg_0_, Column::precomputed_sel_mem_op_reg_1_,
236 Column::precomputed_sel_mem_op_reg_2_, Column::precomputed_sel_mem_op_reg_3_,
237 Column::precomputed_sel_mem_op_reg_4_, Column::precomputed_sel_mem_op_reg_5_,
238 };
239 constexpr std::array<Column, AVM_MAX_REGISTERS> RW_COLUMNS = {
240 Column::precomputed_rw_reg_0_, Column::precomputed_rw_reg_1_, Column::precomputed_rw_reg_2_,
241 Column::precomputed_rw_reg_3_, Column::precomputed_rw_reg_4_, Column::precomputed_rw_reg_5_,
242 };
243 constexpr std::array<Column, AVM_MAX_REGISTERS> DO_TAG_CHECK_COLUMNS = {
244 Column::precomputed_sel_tag_check_reg_0_, Column::precomputed_sel_tag_check_reg_1_,
245 Column::precomputed_sel_tag_check_reg_2_, Column::precomputed_sel_tag_check_reg_3_,
246 Column::precomputed_sel_tag_check_reg_4_, Column::precomputed_sel_tag_check_reg_5_,
247 };
248 constexpr std::array<Column, AVM_MAX_REGISTERS> EXPECTED_TAG_COLUMNS = {
249 Column::precomputed_expected_tag_reg_0_, Column::precomputed_expected_tag_reg_1_,
250 Column::precomputed_expected_tag_reg_2_, Column::precomputed_expected_tag_reg_3_,
251 Column::precomputed_expected_tag_reg_4_, Column::precomputed_expected_tag_reg_5_,
252 };
253
254 constexpr std::array<Column, AVM_MAX_OPERANDS> SEL_OP_IS_ADDRESS_COLUMNS = {
255 Column::precomputed_sel_op_is_address_0_, Column::precomputed_sel_op_is_address_1_,
256 Column::precomputed_sel_op_is_address_2_, Column::precomputed_sel_op_is_address_3_,
257 Column::precomputed_sel_op_is_address_4_, Column::precomputed_sel_op_is_address_5_,
258 Column::precomputed_sel_op_is_address_6_,
259 };
260
261 for (const auto& [exec_opcode, exec_instruction_spec] : get_exec_instruction_spec()) {
262 // Basic information.
263 trace.set(static_cast<uint32_t>(exec_opcode),
264 { {
265 { C::precomputed_sel_exec_spec, 1 },
266 { C::precomputed_exec_opcode_opcode_gas, exec_instruction_spec.gas_cost.opcode_gas },
267 { C::precomputed_exec_opcode_base_da_gas, exec_instruction_spec.gas_cost.base_da },
268 { C::precomputed_exec_opcode_dynamic_l2_gas, exec_instruction_spec.gas_cost.dyn_l2 },
269 { C::precomputed_exec_opcode_dynamic_da_gas, exec_instruction_spec.gas_cost.dyn_da },
270 } });
271
272 // Register information.
273 const auto& register_info = exec_instruction_spec.register_info;
274 for (size_t i = 0; i < AVM_MAX_REGISTERS; i++) {
275 trace.set(MEM_OP_REG_COLUMNS.at(i), static_cast<uint32_t>(exec_opcode), register_info.is_active(i) ? 1 : 0);
276 trace.set(RW_COLUMNS.at(i), static_cast<uint32_t>(exec_opcode), register_info.is_write(i) ? 1 : 0);
277 trace.set(DO_TAG_CHECK_COLUMNS.at(i),
278 static_cast<uint32_t>(exec_opcode),
279 register_info.need_tag_check(i) ? 1 : 0);
280 trace.set(EXPECTED_TAG_COLUMNS.at(i),
281 static_cast<uint32_t>(exec_opcode),
282 static_cast<uint32_t>(register_info.expected_tag(i).value_or(static_cast<ValueTag>(0))));
283 }
284
285 // Whether an operand is an address
286 for (size_t i = 0; i < AVM_MAX_OPERANDS; i++) {
287 trace.set(SEL_OP_IS_ADDRESS_COLUMNS.at(i),
288 static_cast<uint32_t>(exec_opcode),
289 i < exec_instruction_spec.num_addresses ? 1 : 0);
290 }
291
292 // Gadget / Subtrace Selectors / Decomposable selectors
293 auto dispatch_to_subtrace = get_subtrace_info_map().at(exec_opcode);
294 trace.set(static_cast<uint32_t>(exec_opcode),
295 { { { C::precomputed_subtrace_id, get_subtrace_id(dispatch_to_subtrace.subtrace_selector) },
296 { C::precomputed_subtrace_operation_id, dispatch_to_subtrace.subtrace_operation_id },
297 { C::precomputed_dyn_gas_id, exec_instruction_spec.dyn_gas_id } } });
298 }
299}
300
308{
309 const auto& p_limbs_per_radix = get_p_limbs_per_radix();
310
311 trace.reserve_column(C::precomputed_sel_to_radix_p_limb_counts, p_limbs_per_radix.size());
312 trace.reserve_column(C::precomputed_to_radix_safe_limbs, p_limbs_per_radix.size());
313
314 for (size_t i = 0; i < p_limbs_per_radix.size(); ++i) {
315 size_t decomposition_len = p_limbs_per_radix[i].size();
316 trace.set(C::precomputed_sel_to_radix_p_limb_counts, static_cast<uint32_t>(i), 1);
317 // Use 0 as fallback when decomposition_len == 0 (i.e. p_limbs_per_radix[0] and p_limbs_per_radix[1])
318 trace.set(C::precomputed_to_radix_safe_limbs,
319 static_cast<uint32_t>(i),
320 decomposition_len > 0 ? decomposition_len - 1 : 0);
321 trace.set(C::precomputed_to_radix_num_limbs_for_p, static_cast<uint32_t>(i), decomposition_len);
322 }
323}
324
333{
334 const auto& p_limbs_per_radix = get_p_limbs_per_radix();
335
336 uint32_t row = 0;
337 for (size_t i = 0; i < p_limbs_per_radix.size(); ++i) {
338 size_t decomposition_len = p_limbs_per_radix[i].size();
339 for (size_t j = 0; j < decomposition_len; ++j) {
340 trace.set(C::precomputed_sel_p_decomposition, row, 1);
341 trace.set(C::precomputed_p_decomposition_radix, row, i);
342 trace.set(C::precomputed_p_decomposition_limb_index, row, j);
343 trace.set(C::precomputed_p_decomposition_limb, row, p_limbs_per_radix[i][j]);
344 row++;
345 }
346 }
347}
348
355{
356 constexpr uint32_t num_rows = 1 << 8; // 256
357
358 for (uint32_t i = static_cast<uint32_t>(MemoryTag::MAX) + 1; i < num_rows; i++) {
359 trace.set(C::precomputed_sel_mem_tag_out_of_range, i, 1);
360 }
361}
362
369{
370 constexpr uint32_t num_rows = 1 << 16; // 65536
371 trace.reserve_column(C::precomputed_sel_addressing_gas, num_rows);
372 trace.reserve_column(C::precomputed_addressing_gas, num_rows);
373
374 for (uint32_t i = 0; i < num_rows; i++) {
375 trace.set(C::precomputed_sel_addressing_gas, i, 1);
376 trace.set(C::precomputed_addressing_gas, i, compute_addressing_gas(static_cast<uint16_t>(i)));
377 }
378}
379
388{
389 for (const auto& [phase_value, spec] : get_tx_phase_spec_map()) {
390
391 const uint32_t row = static_cast<uint32_t>(phase_value);
392 // Populate all columns that are part of the #[READ_PHASE_SPEC] lookup in tx.pil.
394 { C::precomputed_sel_phase, 1 },
395 { C::precomputed_is_public_call_request, spec.is_public_call_request ? 1 : 0 },
396 { C::precomputed_is_teardown, spec.is_teardown ? 1 : 0 },
397 { C::precomputed_is_collect_fee, spec.is_collect_fee ? 1 : 0 },
398 { C::precomputed_is_tree_padding, spec.is_tree_padding ? 1 : 0 },
399 { C::precomputed_is_cleanup, spec.is_cleanup ? 1 : 0 },
400 { C::precomputed_is_revertible, spec.is_revertible ? 1 : 0 },
401 { C::precomputed_read_pi_start_offset, spec.read_pi_start_offset },
402 { C::precomputed_read_pi_length_offset, spec.read_pi_length_offset },
403 { C::precomputed_sel_append_note_hash, spec.append_note_hash ? 1 : 0 },
404 { C::precomputed_sel_append_nullifier, spec.append_nullifier ? 1 : 0 },
405 { C::precomputed_sel_append_l2_l1_msg, spec.append_l2_l1_msg ? 1 : 0 },
406 { C::precomputed_next_phase_on_revert, spec.next_phase_on_revert },
407 };
408
409 trace.set(row, row_data);
410 }
411}
412
418{
419 uint32_t row = 1;
420 for (const auto& round_constant : simulation::keccak_round_constants) {
421 trace.set(row,
422 { {
423 { C::precomputed_sel_keccak, 1 },
424 { C::precomputed_keccak_round_constant, round_constant },
425 } });
426 row++;
427 }
428}
429
438{
439 constexpr uint32_t NUM_ROWS = 1 << 8;
440
441 constexpr uint8_t NUM_VALID_ENV_VARS = static_cast<uint8_t>(EnvironmentVariable::MAX) + 1;
442
443 for (uint8_t enum_value = 0; enum_value < NUM_VALID_ENV_VARS; enum_value++) {
444 const auto& envvar_spec = GetEnvVarSpec::get_table(enum_value);
445 trace.set(static_cast<uint32_t>(enum_value),
446 { {
447 { C::precomputed_sel_envvar_pi_lookup_col0, envvar_spec.envvar_pi_lookup_col0 },
448 { C::precomputed_sel_envvar_pi_lookup_col1, envvar_spec.envvar_pi_lookup_col1 },
449 { C::precomputed_envvar_pi_row_idx, envvar_spec.envvar_pi_row_idx },
450 { C::precomputed_is_address, envvar_spec.is_address ? 1 : 0 },
451 { C::precomputed_is_sender, envvar_spec.is_sender ? 1 : 0 },
452 { C::precomputed_is_transactionfee, envvar_spec.is_transactionfee ? 1 : 0 },
453 { C::precomputed_is_isstaticcall, envvar_spec.is_isstaticcall ? 1 : 0 },
454 { C::precomputed_is_l2gasleft, envvar_spec.is_l2gasleft ? 1 : 0 },
455 { C::precomputed_is_dagasleft, envvar_spec.is_dagasleft ? 1 : 0 },
456 { C::precomputed_out_tag, envvar_spec.out_tag },
457 } });
458 }
459
460 // Flag invalid enum values (those beyond the valid range) as out-of-range.
461 // Valid rows default to 0 (the trace container's default).
462 for (uint32_t i = NUM_VALID_ENV_VARS; i < NUM_ROWS; i++) {
463 trace.set(C::precomputed_invalid_envvar_enum, i, 1);
464 }
465}
466
474{
475 // Set valid rows based on the precomputed table
476 for (uint8_t enum_value = 0; enum_value <= static_cast<uint8_t>(ContractInstanceMember::MAX); enum_value++) {
477 const auto& spec = GetContractInstanceSpec::get_table(enum_value);
478
479 trace.set(static_cast<uint32_t>(enum_value),
480 { {
481 { C::precomputed_is_valid_member_enum, spec.is_valid_member_enum ? 1 : 0 },
482 { C::precomputed_is_deployer, spec.is_deployer ? 1 : 0 },
483 { C::precomputed_is_class_id, spec.is_class_id ? 1 : 0 },
484 { C::precomputed_is_init_hash, spec.is_init_hash ? 1 : 0 },
485 } });
486 }
487}
488
489} // namespace bb::avm2::tracegen
#define AVM_MAX_OPERANDS
#define AVM_MAX_REGISTERS
static Table get_table(uint8_t member_enum)
Look up the precomputed table entry for a given member enum value.
static Table get_table(uint8_t envvar)
void process_sha256_round_constants(TraceContainer &trace)
Populate the 64 SHA-256 round constants (K_0 .. K_63) and their selector. The sel_sha256_compression ...
void process_to_radix_p_decompositions(TraceContainer &trace)
Populate the TORADIXBE p-decomposition table.
void process_misc(TraceContainer &trace, const uint32_t num_rows=PRECOMPUTED_TRACE_SIZE)
Populate miscellaneous precomputed columns: first_row selector and idx (row index).
void process_wire_instruction_spec(TraceContainer &trace)
Populate the wire-level instruction specification table.
void process_bitwise(TraceContainer &trace)
Populate the 8-bit bitwise lookup table (AND, OR, XOR).
void process_keccak_round_constants(TraceContainer &trace)
Populate the 24 Keccak-f[1600] round constants and their selector. Row 0 is intentionally left empty ...
void process_to_radix_safe_limbs(TraceContainer &trace)
Populate the TORADIXBE safe-limbs table (one row per radix 0..255).
void process_memory_tag_range(TraceContainer &trace)
Populate the memory tag out-of-range selector.
void process_exec_instruction_spec(TraceContainer &trace)
Populate the execution-level instruction specification table.
void process_get_env_var_table(TraceContainer &trace)
Populate the GETENVVAR lookup table.
void process_power_of_2(TraceContainer &trace)
Generate a column where row i holds 2^i, for i in [0, 255], for the values of 254 and 255 the values ...
void process_get_contract_instance_table(TraceContainer &trace)
Populate the GETCONTRACTINSTANCE lookup table.
void process_phase_table(TraceContainer &trace)
Populate the transaction phase specification table.
void process_addressing_gas(TraceContainer &trace)
Populate the addressing-mode gas lookup table (65536 rows).
void process_sel_range_16(TraceContainer &trace)
Generate a selector column that activates the first 2^16 (65536) rows.
void process_tag_parameters(TraceContainer &trace)
Populate the memory tag parameters table (byte length, max bits, max value per tag).
void process_sel_range_8(TraceContainer &trace)
Generate a selector column that activates the first 2^8 (256) rows.
TestTraceContainer trace
FF a
FF b
constexpr std::array< uint64_t, 24 > keccak_round_constants
constexpr uint32_t round_constants[64]
const std::unordered_map< TransactionPhase, TxPhaseSpec > & get_tx_phase_spec_map()
const std::unordered_map< ExecutionOpCode, SubtraceInfo > & get_subtrace_info_map()
constexpr uint32_t PRECOMPUTED_TRACE_SIZE
FF get_subtrace_id(SubtraceSel subtrace_sel)
Get the subtrace ID for a given subtrace enum.
const std::array< std::vector< uint8_t >, 257 > & get_p_limbs_per_radix()
Gets the p limbs per radix array. Each element is a vector containing the little endian decomposition...
Definition to_radix.cpp:60
AvmFlavorSettings::FF FF
Definition field.hpp:10
const std::unordered_map< WireOpCode, WireInstructionSpec > & get_wire_instruction_spec()
const std::unordered_map< ExecutionOpCode, ExecInstructionSpec > & get_exec_instruction_spec()
uint8_t get_tag_bits(ValueTag tag)
uint256_t get_tag_max_value(ValueTag tag)
constexpr size_t NUM_OP_DC_SELECTORS
uint16_t compute_addressing_gas(uint16_t addressing_mode)
Computes the gas cost for addressing.
Definition gas.cpp:16
ValueTag MemoryTag
uint8_t get_tag_bytes(ValueTag tag)
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13