29const FF& get_tag_inverse(
size_t index)
31 constexpr size_t NUM_TAGS =
static_cast<size_t>(
MemoryTag::MAX) + 1;
34 for (
size_t i = 0; i < NUM_TAGS; i++) {
35 inverses.at(i) =
FF(i);
41 return tag_inverses.at(
index);
53 if (
static_cast<uint8_t
>(a_tag) >=
static_cast<uint8_t
>(b_tag)) {
54 return get_tag_inverse(
static_cast<uint8_t
>(a_tag) -
static_cast<uint8_t
>(b_tag));
57 return -get_tag_inverse(
static_cast<uint8_t
>(b_tag) -
static_cast<uint8_t
>(a_tag));
68 const MemoryTag a_tag =
event.a.get_tag();
71 bool has_error =
event.error;
73 switch (
event.operation) {
75 return { { C::alu_sel_op_add, 1 },
80 { C::alu_cf, !has_error && (
event.a.as_ff() +
event.b.as_ff() !=
event.c.as_ff()) ? 1 : 0 } };
82 return { { C::alu_sel_op_sub, 1 },
87 { C::alu_cf, !has_error && (
event.a.as_ff() -
event.b.as_ff() !=
event.c.as_ff()) ? 1 : 0 } };
94 { C::alu_sel_op_mul, 1 },
96 { C::alu_constant_64, 64 },
97 { C::alu_sel_mul_no_err_non_ff, (has_error || is_ff) ? 0 : 1 },
107 uint256_t hi_operand = (((a_int * b_int) >> 128) -
109 res.insert(res.end(),
111 { C::alu_sel_mul_div_u128, 1 },
112 { C::alu_sel_decompose_a, 1 },
113 { C::alu_a_lo_bits, 64 },
114 { C::alu_a_hi_bits, 64 },
115 { C::alu_a_lo, a_decomp.lo },
116 { C::alu_a_hi, a_decomp.hi },
117 { C::alu_b_lo, b_decomp.lo },
118 { C::alu_b_hi, b_decomp.hi },
120 { C::alu_cf, hi_operand >> 64 },
135 { C::alu_sel_op_div, 1 },
137 { C::alu_constant_64, 64 },
138 { C::alu_b_inv,
event.b.as_ff() },
142 auto remainder =
event.a -
event.b *
event.c;
143 res.insert(res.end(),
145 { C::alu_sel_div_no_err, 1 },
146 { C::alu_helper1, remainder.as_ff() },
147 { C::alu_sel_int_gt, 1 },
148 { C::alu_gt_input_a,
event.b.as_ff() },
149 { C::alu_gt_input_b, remainder.as_ff() },
150 { C::alu_gt_result_c, 1 },
156 res.insert(res.end(),
158 { C::alu_sel_mul_div_u128, 1 },
159 { C::alu_sel_decompose_a, 1 },
160 { C::alu_a_lo_bits, 64 },
161 { C::alu_a_hi_bits, 64 },
162 { C::alu_a_lo, c_decomp.lo },
163 { C::alu_a_hi, c_decomp.hi },
164 { C::alu_b_lo, b_decomp.lo },
165 { C::alu_b_hi, b_decomp.hi },
173 { C::alu_sel_op_fdiv, 1 },
175 { C::alu_b_inv,
event.b.as_ff() },
179 const FF diff =
event.a.as_ff() -
event.b.as_ff();
181 { C::alu_sel_op_eq, 1 },
183 { C::alu_ab_diff_inv, has_error ? 0 : diff },
189 { C::alu_sel_op_lt, 1 },
191 { C::alu_gt_input_a,
event.b },
192 { C::alu_gt_input_b,
event.a },
197 res.insert(res.end(),
199 { C::alu_gt_result_c, event.c.as_ff() == 1 ? 1 : 0 },
200 { C::alu_sel_ff_gt, is_ff ? 1 : 0 },
201 { C::alu_sel_int_gt, is_ff ? 0 : 1 },
209 { C::alu_sel_op_lte, 1 },
211 { C::alu_gt_input_a,
event.a },
212 { C::alu_gt_input_b,
event.b },
217 res.insert(res.end(),
219 { C::alu_gt_result_c, event.c.as_ff() == 0 ? 1 : 0 },
220 { C::alu_sel_ff_gt, is_ff ? 1 : 0 },
221 { C::alu_sel_int_gt, is_ff ? 0 : 1 },
228 { C::alu_sel_op_not, 1 },
235 { C::alu_sel_op_shl, 1 },
244 bool overflow = b_num > max_bits;
247 uint128_t a_lo_bits = overflow ? max_bits : max_bits - b_num;
254 overflow ? b_num - max_bits : a_num & mask;
255 uint128_t a_hi = a_lo_bits >= 128 ? 0 : a_num >> a_lo_bits;
256 uint128_t a_hi_bits = overflow ? max_bits : b_num;
260 { C::alu_sel_shift_ops_no_overflow, overflow ? 0 : 1 },
261 { C::alu_sel_decompose_a, 1 },
262 { C::alu_a_lo, a_lo },
263 { C::alu_a_lo_bits, a_lo_bits },
264 { C::alu_a_hi, a_hi },
265 { C::alu_a_hi_bits, a_hi_bits },
266 { C::alu_shift_lo_bits, a_lo_bits },
267 { C::alu_two_pow_shift_lo_bits,
277 { C::alu_sel_op_shr, 1 },
286 bool overflow = b_num > max_bits;
289 uint8_t a_lo_bits = overflow ? max_bits :
static_cast<uint8_t
>(b_num);
296 overflow ? b_num - max_bits : a_num & mask;
297 uint128_t a_hi = a_lo_bits >= 128 ? 0 : a_num >> a_lo_bits;
298 uint128_t a_hi_bits = overflow ? max_bits : max_bits - b_num;
299 res.insert(res.end(),
301 { C::alu_sel_shift_ops_no_overflow, overflow ? 0 : 1 },
302 { C::alu_sel_decompose_a, 1 },
303 { C::alu_a_lo, a_lo },
304 { C::alu_a_lo_bits, a_lo_bits },
305 { C::alu_a_hi, a_hi },
306 { C::alu_a_hi_bits, a_hi_bits },
307 { C::alu_shift_lo_bits, a_lo_bits },
308 { C::alu_two_pow_shift_lo_bits,
318 bool is_lt_128 = !is_trivial && value < (static_cast<uint256_t>(1) << 128);
319 bool is_gte_128 = !is_trivial && !is_lt_128;
326 { C::alu_sel_op_truncate, 1 },
328 { C::alu_sel_trunc_trivial, is_trivial ? 1 : 0 },
329 { C::alu_sel_trunc_lt_128, is_lt_128 ? 1 : 0 },
330 { C::alu_sel_trunc_gte_128, is_gte_128 ? 1 : 0 },
331 { C::alu_sel_trunc_non_trivial, is_trivial ? 0 : 1 },
332 { C::alu_a_lo, lo_128 },
334 { C::alu_mid_bits, is_trivial ? 0 : 128 - dst_bits },
338 throw std::runtime_error(
"Unknown ALU operation");
357 const MemoryTag a_tag =
event.a.get_tag();
358 const FF a_tag_ff =
static_cast<FF>(
static_cast<uint8_t
>(a_tag));
359 const MemoryTag b_tag =
event.b.get_tag();
360 const FF b_tag_ff =
static_cast<FF>(
static_cast<uint8_t
>(b_tag));
363 { C::alu_sel_err, 1 },
379 event.b.as_ff() == 0;
381 if (ab_tags_mismatch || ff_tag_err) {
382 error_columns.push_back({ C::alu_sel_tag_err, 1 });
387 if (ab_tags_mismatch) {
388 error_columns.push_back({ C::alu_sel_ab_tag_mismatch, 1 });
389 error_columns.push_back({ C::alu_ab_tags_diff_inv, get_tag_diff_inverse(a_tag, b_tag) });
393 error_columns.push_back({ C::alu_sel_div_0_err, 1 });
397 BB_ASSERT(error_columns.size() != 1,
"ALU Event emitted with an error, but none exists");
399 return error_columns;
417 for (
const auto&
event : events) {
421 ?
static_cast<MemoryTag>(
static_cast<uint8_t
>(
event.b.as_ff()))
423 const FF b_tag =
static_cast<FF>(
static_cast<uint8_t
>(
event.b.get_tag()));
424 const FF c_tag =
static_cast<FF>(
static_cast<uint8_t
>(
event.c.get_tag()));
431 trace.set(row, get_operation_specific_columns(
event));
441 { C::alu_ia,
event.a },
443 { C::alu_ic,
event.c },
444 { C::alu_ia_tag,
static_cast<uint8_t
>(a_tag) },
445 { C::alu_ib_tag, b_tag },
446 { C::alu_ic_tag, c_tag },
450 { C::alu_tag_ff_diff_inv, get_tag_diff_inverse(a_tag,
MemoryTag::FF) },
452 { C::alu_tag_u128_diff_inv, get_tag_diff_inverse(a_tag,
MemoryTag::U128) },
459 trace.invert_columns({ { C::alu_ab_diff_inv, C::alu_b_inv } });
465 .add<lookup_alu_range_check_decomposition_a_lo_settings, InteractionType::LookupGeneric>(C::range_check_sel)
467 .add<lookup_alu_range_check_decomposition_b_lo_settings, InteractionType::LookupGeneric>(C::range_check_sel)
469 .add<lookup_alu_range_check_mul_c_hi_settings, InteractionType::LookupGeneric>(C::range_check_sel)
471 .add<lookup_alu_int_gt_settings, InteractionType::LookupGeneric>(C::gt_sel)
473 .add<lookup_alu_range_check_trunc_mid_settings, InteractionType::LookupGeneric>(C::range_check_sel)
#define BB_ASSERT(expression,...)
#define AVM_EXEC_OP_ID_ALU_TRUNCATE
#define AVM_EXEC_OP_ID_ALU_LTE
#define AVM_EXEC_OP_ID_ALU_DIV
#define AVM_EXEC_OP_ID_ALU_ADD
#define AVM_EXEC_OP_ID_ALU_SHL
#define AVM_EXEC_OP_ID_ALU_EQ
#define AVM_EXEC_OP_ID_ALU_SUB
#define AVM_EXEC_OP_ID_ALU_NOT
#define AVM_EXEC_OP_ID_ALU_MUL
#define AVM_EXEC_OP_ID_ALU_FDIV
#define AVM_EXEC_OP_ID_ALU_SHR
#define AVM_EXEC_OP_ID_ALU_LT
std::vector< Event > Container
static const InteractionDefinition interactions
void process(const simulation::EventEmitterInterface< simulation::AluEvent >::Container &events, TraceContainer &trace)
Process the ALU events and populate the ALU relevant columns in the trace.
InteractionDefinition & add(auto &&... args)
static constexpr uint256_t from_uint128(const uint128_t a) noexcept
U128Decomposition decompose_128(const uint128_t &x)
lookup_settings< lookup_alu_range_check_decomposition_a_hi_settings_ > lookup_alu_range_check_decomposition_a_hi_settings
lookup_settings< lookup_alu_tag_max_bits_value_settings_ > lookup_alu_tag_max_bits_value_settings
constexpr uint128_t MASK_64
constexpr uint256_t MASK_128
lookup_settings< lookup_alu_large_trunc_canonical_dec_settings_ > lookup_alu_large_trunc_canonical_dec_settings
lookup_settings< lookup_alu_ff_gt_settings_ > lookup_alu_ff_gt_settings
uint8_t get_tag_bits(ValueTag tag)
lookup_settings< lookup_alu_shifts_two_pow_settings_ > lookup_alu_shifts_two_pow_settings
uint256_t get_tag_max_value(ValueTag tag)
lookup_settings< lookup_alu_range_check_decomposition_b_hi_settings_ > lookup_alu_range_check_decomposition_b_hi_settings
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
simulation::PublicDataTreeReadWriteEvent event
unsigned __int128 uint128_t
static void batch_invert(C &coeffs) noexcept