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 <cstddef>
5#include <cstdint>
6#include <vector>
7
20
21namespace bb::avm2::tracegen {
22
23using C = Column;
24
25void PrecomputedTraceBuilder::process_misc(TraceContainer& trace, const uint32_t num_rows)
26{
27 // First row.
28 trace.set(C::precomputed_first_row, 0, 1);
29
30 // Idx
31 trace.reserve_column(C::precomputed_idx, num_rows);
32 for (uint32_t i = 0; i < num_rows; i++) {
33 trace.set(C::precomputed_idx, i, i);
34 }
35}
36
38{
39 // 256 per input (a and b), and 3 different bitwise ops
40 constexpr auto num_rows = 256 * 256;
41 static_assert(num_rows <= PRECOMPUTED_TRACE_SIZE);
42 trace.reserve_column(C::precomputed_bitwise_input_a, num_rows);
43 trace.reserve_column(C::precomputed_bitwise_input_b, num_rows);
44 trace.reserve_column(C::precomputed_bitwise_output_and, num_rows);
45 trace.reserve_column(C::precomputed_bitwise_output_or, num_rows);
46 trace.reserve_column(C::precomputed_bitwise_output_xor, num_rows);
47
48 // row # is derived as:
49 // - input_b: bits 0...7 (0 being LSB)
50 // - input_a: bits 8...15
51 for (uint32_t a = 0; a < 256; a++) {
52 for (uint32_t b = 0; b < 256; b++) {
53 trace.set((a << 8) | b,
54 { {
55 { C::precomputed_bitwise_input_a, FF(a) },
56 { C::precomputed_bitwise_input_b, FF(b) },
57 { C::precomputed_bitwise_output_and, FF(a & b) },
58 { C::precomputed_bitwise_output_or, FF(a | b) },
59 { C::precomputed_bitwise_output_xor, FF(a ^ b) },
60 } });
61 }
62 }
63}
64
72{
73 constexpr auto num_rows = 1 << 8; // 256
74 // Set this selector high for the first 2^8 rows
75 // For these rows, idx will be 0...255
76 trace.reserve_column(C::precomputed_sel_range_8, num_rows);
77 for (uint32_t i = 0; i < num_rows; i++) {
78 trace.set(C::precomputed_sel_range_8, i, 1);
79 }
80}
81
89{
90 constexpr auto num_rows = 1 << 16; // 2^16
91 // Set this selector high for the first 2^16 rows
92 // For these rows, idx will be 0...2^16-1
93 trace.reserve_column(C::precomputed_sel_range_16, num_rows);
94 for (uint32_t i = 0; i < num_rows; i++) {
95 trace.set(C::precomputed_sel_range_16, i, 1);
96 }
97}
98
104{
105 constexpr auto num_rows = 1 << 8; // 2^8 = 256
106 trace.reserve_column(C::precomputed_power_of_2, num_rows);
107 for (uint32_t i = 0; i < num_rows; i++) {
108 trace.set(C::precomputed_power_of_2, i, uint256_t(1) << uint256_t(i));
109 }
110}
111
113{
114 constexpr std::array<uint32_t, 64> round_constants{
115 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
116 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
117 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
118 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
119 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
120 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
121 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
122 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
123 };
124 constexpr auto num_rows = round_constants.size();
125 trace.reserve_column(C::precomputed_sha256_compression_round_constant, num_rows);
126 trace.reserve_column(C::precomputed_sel_sha256_compression, num_rows);
127 for (uint32_t i = 0; i < num_rows; i++) {
128 trace.set(i,
129 { { { C::precomputed_sel_sha256_compression, 1 },
130 { C::precomputed_sha256_compression_round_constant, round_constants[i] } } });
131 }
132}
133
135{
137
138 constexpr uint32_t NUM_TAGS = static_cast<uint32_t>(MemoryTag::MAX) + 1;
139 for (uint32_t i = 0; i < NUM_TAGS; i++) {
140 const auto tag = static_cast<MemoryTag>(i);
141 trace.set(i, // Column number corresponds to MemoryTag enum value.
142 { {
143 { C::precomputed_sel_tag_parameters, 1 },
144 { C::precomputed_tag_byte_length, get_tag_bytes(tag) },
145 { C::precomputed_tag_max_bits, get_tag_bits(tag) },
146 { C::precomputed_tag_max_value, get_tag_max_value(tag) },
147 } });
148 }
149}
150
152{
153 const std::array<Column, NUM_OP_DC_SELECTORS> sel_op_dc_columns = {
154 C::precomputed_sel_op_dc_0, C::precomputed_sel_op_dc_1, C::precomputed_sel_op_dc_2,
155 C::precomputed_sel_op_dc_3, C::precomputed_sel_op_dc_4, C::precomputed_sel_op_dc_5,
156 C::precomputed_sel_op_dc_6, C::precomputed_sel_op_dc_7, C::precomputed_sel_op_dc_8,
157 C::precomputed_sel_op_dc_9, C::precomputed_sel_op_dc_10, C::precomputed_sel_op_dc_11,
158 C::precomputed_sel_op_dc_12, C::precomputed_sel_op_dc_13, C::precomputed_sel_op_dc_14,
159 C::precomputed_sel_op_dc_15, C::precomputed_sel_op_dc_16, C::precomputed_sel_op_dc_17,
160 };
161
162 // First set the selector for this table lookup.
163 constexpr uint32_t num_rows = 1 << 8; // 256
164 constexpr uint32_t num_opcodes = static_cast<uint32_t>(WireOpCode::LAST_OPCODE_SENTINEL);
165 trace.reserve_column(C::precomputed_opcode_out_of_range, num_rows - num_opcodes);
166 for (uint32_t i = num_opcodes; i < num_rows; i++) {
167 trace.set(C::precomputed_opcode_out_of_range, i, 1);
168 }
169
170 for (size_t i = 0; i < NUM_OP_DC_SELECTORS; i++) {
171 trace.reserve_column(sel_op_dc_columns.at(i), num_opcodes);
172 }
173 trace.reserve_column(C::precomputed_exec_opcode, num_opcodes);
174 trace.reserve_column(C::precomputed_instr_size, num_opcodes);
175
176 // Fill the lookup tables with the operand decomposition selectors.
177 for (const auto& [wire_opcode, wire_instruction_spec] : get_wire_instruction_spec()) {
178 for (size_t i = 0; i < NUM_OP_DC_SELECTORS; i++) {
179 trace.set(sel_op_dc_columns.at(i),
180 static_cast<uint32_t>(wire_opcode),
181 wire_instruction_spec.op_dc_selectors.at(i));
182 }
183 trace.set(C::precomputed_exec_opcode,
184 static_cast<uint32_t>(wire_opcode),
185 static_cast<uint32_t>(wire_instruction_spec.exec_opcode));
186 trace.set(C::precomputed_instr_size, static_cast<uint32_t>(wire_opcode), wire_instruction_spec.size_in_bytes);
187
188 if (wire_instruction_spec.tag_operand_idx.has_value()) {
189 trace.set(C::precomputed_sel_has_tag, static_cast<uint32_t>(wire_opcode), 1);
190
191 if (wire_instruction_spec.tag_operand_idx.value() == 2) {
192 trace.set(C::precomputed_sel_tag_is_op2, static_cast<uint32_t>(wire_opcode), 1);
193 }
194 }
195 }
196}
197
199{
200 constexpr std::array<Column, AVM_MAX_REGISTERS> MEM_OP_REG_COLUMNS = {
201 Column::precomputed_sel_mem_op_reg_0_, Column::precomputed_sel_mem_op_reg_1_,
202 Column::precomputed_sel_mem_op_reg_2_, Column::precomputed_sel_mem_op_reg_3_,
203 Column::precomputed_sel_mem_op_reg_4_, Column::precomputed_sel_mem_op_reg_5_,
204 };
205 constexpr std::array<Column, AVM_MAX_REGISTERS> RW_COLUMNS = {
206 Column::precomputed_rw_reg_0_, Column::precomputed_rw_reg_1_, Column::precomputed_rw_reg_2_,
207 Column::precomputed_rw_reg_3_, Column::precomputed_rw_reg_4_, Column::precomputed_rw_reg_5_,
208 };
209 constexpr std::array<Column, AVM_MAX_REGISTERS> DO_TAG_CHECK_COLUMNS = {
210 Column::precomputed_sel_tag_check_reg_0_, Column::precomputed_sel_tag_check_reg_1_,
211 Column::precomputed_sel_tag_check_reg_2_, Column::precomputed_sel_tag_check_reg_3_,
212 Column::precomputed_sel_tag_check_reg_4_, Column::precomputed_sel_tag_check_reg_5_,
213 };
214 constexpr std::array<Column, AVM_MAX_REGISTERS> EXPECTED_TAG_COLUMNS = {
215 Column::precomputed_expected_tag_reg_0_, Column::precomputed_expected_tag_reg_1_,
216 Column::precomputed_expected_tag_reg_2_, Column::precomputed_expected_tag_reg_3_,
217 Column::precomputed_expected_tag_reg_4_, Column::precomputed_expected_tag_reg_5_,
218 };
219
220 constexpr std::array<Column, AVM_MAX_OPERANDS> SEL_OP_IS_ADDRESS_COLUMNS = {
221 Column::precomputed_sel_op_is_address_0_, Column::precomputed_sel_op_is_address_1_,
222 Column::precomputed_sel_op_is_address_2_, Column::precomputed_sel_op_is_address_3_,
223 Column::precomputed_sel_op_is_address_4_, Column::precomputed_sel_op_is_address_5_,
224 Column::precomputed_sel_op_is_address_6_,
225 };
226
227 for (const auto& [exec_opcode, exec_instruction_spec] : get_exec_instruction_spec()) {
228 // Basic information.
229 trace.set(static_cast<uint32_t>(exec_opcode),
230 { {
231 { C::precomputed_sel_exec_spec, 1 },
232 { C::precomputed_exec_opcode_opcode_gas, exec_instruction_spec.gas_cost.opcode_gas },
233 { C::precomputed_exec_opcode_base_da_gas, exec_instruction_spec.gas_cost.base_da },
234 { C::precomputed_exec_opcode_dynamic_l2_gas, exec_instruction_spec.gas_cost.dyn_l2 },
235 { C::precomputed_exec_opcode_dynamic_da_gas, exec_instruction_spec.gas_cost.dyn_da },
236 } });
237
238 // Register information.
239 const auto& register_info = get_exec_instruction_spec().at(exec_opcode).register_info;
240 for (size_t i = 0; i < AVM_MAX_REGISTERS; i++) {
241 trace.set(MEM_OP_REG_COLUMNS.at(i), static_cast<uint32_t>(exec_opcode), register_info.is_active(i) ? 1 : 0);
242 trace.set(RW_COLUMNS.at(i), static_cast<uint32_t>(exec_opcode), register_info.is_write(i) ? 1 : 0);
243 trace.set(DO_TAG_CHECK_COLUMNS.at(i),
244 static_cast<uint32_t>(exec_opcode),
245 register_info.need_tag_check(i) ? 1 : 0);
246 trace.set(EXPECTED_TAG_COLUMNS.at(i),
247 static_cast<uint32_t>(exec_opcode),
248 static_cast<uint32_t>(register_info.expected_tag(i).value_or(static_cast<ValueTag>(0))));
249 }
250
251 // Whether an operand is an address
252 for (size_t i = 0; i < AVM_MAX_OPERANDS; i++) {
253 trace.set(SEL_OP_IS_ADDRESS_COLUMNS.at(i),
254 static_cast<uint32_t>(exec_opcode),
255 i < exec_instruction_spec.num_addresses ? 1 : 0);
256 }
257
258 // Gadget / Subtrace Selectors / Decomposable selectors
259 auto dispatch_to_subtrace = get_subtrace_info_map().at(exec_opcode);
260 trace.set(static_cast<uint32_t>(exec_opcode),
261 { { { C::precomputed_subtrace_id, get_subtrace_id(dispatch_to_subtrace.subtrace_selector) },
262 { C::precomputed_subtrace_operation_id, dispatch_to_subtrace.subtrace_operation_id },
263 { C::precomputed_dyn_gas_id, exec_instruction_spec.dyn_gas_id } } });
264 }
265}
266
268{
269 const auto& p_limbs_per_radix = get_p_limbs_per_radix();
270
271 trace.reserve_column(C::precomputed_sel_to_radix_p_limb_counts, p_limbs_per_radix.size());
272 trace.reserve_column(C::precomputed_to_radix_safe_limbs, p_limbs_per_radix.size());
273
274 for (size_t i = 0; i < p_limbs_per_radix.size(); ++i) {
275 size_t decomposition_len = p_limbs_per_radix[i].size();
276 trace.set(C::precomputed_sel_to_radix_p_limb_counts, static_cast<uint32_t>(i), 1);
277 // Use 0 as fallback when decomposition_len == 0 (i.e. p_limbs_per_radix[0] and p_limbs_per_radix[1])
278 trace.set(C::precomputed_to_radix_safe_limbs,
279 static_cast<uint32_t>(i),
280 decomposition_len > 0 ? decomposition_len - 1 : 0);
281 trace.set(C::precomputed_to_radix_num_limbs_for_p, static_cast<uint32_t>(i), decomposition_len);
282 }
283}
284
286{
287 const auto& p_limbs_per_radix = get_p_limbs_per_radix();
288
289 uint32_t row = 0;
290 for (size_t i = 0; i < p_limbs_per_radix.size(); ++i) {
291 size_t decomposition_len = p_limbs_per_radix[i].size();
292 for (size_t j = 0; j < decomposition_len; ++j) {
293 trace.set(C::precomputed_sel_p_decomposition, row, 1);
294 trace.set(C::precomputed_p_decomposition_radix, row, i);
295 trace.set(C::precomputed_p_decomposition_limb_index, row, j);
296 trace.set(C::precomputed_p_decomposition_limb, row, p_limbs_per_radix[i][j]);
297 row++;
298 }
299 }
300}
301
303{
304 constexpr uint32_t num_rows = 1 << 8; // 256
305
306 for (uint32_t i = static_cast<uint32_t>(MemoryTag::MAX) + 1; i < num_rows; i++) {
307 trace.set(C::precomputed_sel_mem_tag_out_of_range, i, 1);
308 }
309}
310
312{
313 constexpr uint32_t num_rows = 1 << 16; // 65536
314 trace.reserve_column(C::precomputed_sel_addressing_gas, num_rows);
315 trace.reserve_column(C::precomputed_addressing_gas, num_rows);
316
317 for (uint32_t i = 0; i < num_rows; i++) {
318 trace.set(C::precomputed_sel_addressing_gas, i, 1);
319 trace.set(C::precomputed_addressing_gas, i, compute_addressing_gas(static_cast<uint16_t>(i)));
320 }
321}
322
324{
325 using C = Column;
326
327 for (const auto& [phase_value, spec] : get_tx_phase_spec_map()) {
328
329 const uint32_t row = static_cast<uint32_t>(phase_value);
330 // Populate all columns that are part of the #[READ_PHASE_SPEC] lookup in tx.pil.
332 { C::precomputed_sel_phase, 1 },
333 { C::precomputed_is_public_call_request, spec.is_public_call_request ? 1 : 0 },
334 { C::precomputed_is_teardown, spec.is_teardown ? 1 : 0 },
335 { C::precomputed_is_collect_fee, spec.is_collect_fee ? 1 : 0 },
336 { C::precomputed_is_tree_padding, spec.is_tree_padding ? 1 : 0 },
337 { C::precomputed_is_cleanup, spec.is_cleanup ? 1 : 0 },
338 { C::precomputed_is_revertible, spec.is_revertible ? 1 : 0 },
339 { C::precomputed_read_pi_start_offset, spec.read_pi_start_offset },
340 { C::precomputed_read_pi_length_offset, spec.read_pi_length_offset },
341 { C::precomputed_sel_non_revertible_append_note_hash, spec.non_revertible_append_note_hash ? 1 : 0 },
342 { C::precomputed_sel_non_revertible_append_nullifier, spec.non_revertible_append_nullifier ? 1 : 0 },
343 { C::precomputed_sel_non_revertible_append_l2_l1_msg, spec.non_revertible_append_l2_l1_msg ? 1 : 0 },
344 { C::precomputed_sel_revertible_append_note_hash, spec.revertible_append_note_hash ? 1 : 0 },
345 { C::precomputed_sel_revertible_append_nullifier, spec.revertible_append_nullifier ? 1 : 0 },
346 { C::precomputed_sel_revertible_append_l2_l1_msg, spec.revertible_append_l2_l1_msg ? 1 : 0 },
347 { C::precomputed_next_phase_on_revert, spec.next_phase_on_revert },
348 };
349
350 trace.set(row, row_data);
351 }
352}
353
355{
356 uint32_t row = 1;
357 for (const auto& round_constant : simulation::keccak_round_constants) {
358 trace.set(row,
359 { {
360 { C::precomputed_sel_keccak, 1 },
361 { C::precomputed_keccak_round_constant, round_constant },
362 } });
363 row++;
364 }
365}
366
371{
372 constexpr uint32_t NUM_ROWS = 1 << 8;
373
374 // Start by flagging `invalid_envvar_enum` as 1 for all rows.
375 // "valid" rows will be reset manually to 0 below.
376 for (uint32_t i = 0; i < NUM_ROWS; i++) {
377 trace.set(C::precomputed_invalid_envvar_enum, i, 1);
378 }
379
380 for (uint8_t enum_value = 0; enum_value <= static_cast<uint8_t>(EnvironmentVariable::MAX); enum_value++) {
381 const auto& envvar_spec = GetEnvVarSpec::get_table(enum_value);
382 trace.set(static_cast<uint32_t>(enum_value),
383 { {
384 { C::precomputed_invalid_envvar_enum, 0 }, // Reset the invalid enum flag for valid rows
385 { C::precomputed_sel_envvar_pi_lookup_col0, envvar_spec.envvar_pi_lookup_col0 },
386 { C::precomputed_sel_envvar_pi_lookup_col1, envvar_spec.envvar_pi_lookup_col1 },
387 { C::precomputed_envvar_pi_row_idx, envvar_spec.envvar_pi_row_idx },
388 { C::precomputed_is_address, envvar_spec.is_address ? 1 : 0 },
389 { C::precomputed_is_sender, envvar_spec.is_sender ? 1 : 0 },
390 { C::precomputed_is_transactionfee, envvar_spec.is_transactionfee ? 1 : 0 },
391 { C::precomputed_is_isstaticcall, envvar_spec.is_isstaticcall ? 1 : 0 },
392 { C::precomputed_is_l2gasleft, envvar_spec.is_l2gasleft ? 1 : 0 },
393 { C::precomputed_is_dagasleft, envvar_spec.is_dagasleft ? 1 : 0 },
394 { C::precomputed_out_tag, envvar_spec.out_tag },
395 } });
396 }
397}
398
403{
404 // Set valid rows based on the precomputed table
405 for (uint8_t enum_value = 0; enum_value <= static_cast<uint8_t>(ContractInstanceMember::MAX); enum_value++) {
406 const auto& spec = GetContractInstanceSpec::get_table(enum_value);
407
408 trace.set(static_cast<uint32_t>(enum_value),
409 { {
410 { C::precomputed_is_valid_member_enum, spec.is_valid_member_enum ? 1 : 0 },
411 { C::precomputed_is_deployer, spec.is_deployer ? 1 : 0 },
412 { C::precomputed_is_class_id, spec.is_class_id ? 1 : 0 },
413 { C::precomputed_is_init_hash, spec.is_init_hash ? 1 : 0 },
414 } });
415 }
416}
417
418} // namespace bb::avm2::tracegen
#define AVM_MAX_OPERANDS
#define AVM_MAX_REGISTERS
static Table get_table(uint8_t envvar)
void process_sha256_round_constants(TraceContainer &trace)
void process_to_radix_p_decompositions(TraceContainer &trace)
void process_misc(TraceContainer &trace, const uint32_t num_rows=PRECOMPUTED_TRACE_SIZE)
void process_wire_instruction_spec(TraceContainer &trace)
void process_keccak_round_constants(TraceContainer &trace)
void process_to_radix_safe_limbs(TraceContainer &trace)
void process_memory_tag_range(TraceContainer &trace)
void process_exec_instruction_spec(TraceContainer &trace)
void process_get_env_var_table(TraceContainer &trace)
void process_get_contract_instance_table(TraceContainer &trace)
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