39 for (
const auto&
event : events) {
41 const uint32_t radix =
event.radix;
42 BB_ASSERT(radix >= 2 && radix <= 256,
"Invalid radix");
43 const auto& p_limbs = p_limbs_per_radix[
static_cast<size_t>(radix)];
49 const uint32_t safe_limbs =
static_cast<uint32_t
>(p_limbs.size()) - 1;
54 bool acc_under_p =
false;
56 for (uint32_t i = 0; i <
event.limbs.size(); ++i) {
57 const bool is_padding = i > safe_limbs;
58 const uint8_t limb =
event.limbs[i];
59 const uint8_t p_limb = is_padding ? 0 : p_limbs[
static_cast<size_t>(i)];
63 acc_under_p = limb < p_limb;
70 limb_p_diff = limb - p_limb - 1;
71 }
else if (limb < p_limb) {
72 limb_p_diff = p_limb - limb - 1;
75 bool is_unsafe_limb = i == safe_limbs;
76 FF safety_diff =
FF(i) -
FF(safe_limbs);
78 acc += power *
FF(limb);
83 bool end = i == (
event.limbs.size() - 1);
87 { C::to_radix_sel, 1 },
88 { C::to_radix_value,
value },
89 { C::to_radix_radix, radix },
90 { C::to_radix_limb_index, i },
91 { C::to_radix_limb, limb },
92 { C::to_radix_start, i == 0 ? 1 : 0 },
93 { C::to_radix_end, end ? 1 : 0 },
94 { C::to_radix_power, power },
95 { C::to_radix_not_padding_limb, !is_padding ? 1 : 0 },
96 { C::to_radix_acc, acc },
97 { C::to_radix_found, found ? 1 : 0 },
98 { C::to_radix_limb_radix_diff, radix - limb - 1 },
99 { C::to_radix_rem_inverse, rem },
100 { C::to_radix_safe_limbs, safe_limbs },
101 { C::to_radix_is_unsafe_limb, is_unsafe_limb ? 1 : 0 },
102 { C::to_radix_safety_diff_inverse, safety_diff },
103 { C::to_radix_p_limb, p_limb },
104 { C::to_radix_acc_under_p, acc_under_p ? 1 : 0 },
105 { C::to_radix_limb_lt_p, limb < p_limb ? 1 : 0 },
106 { C::to_radix_limb_eq_p, limb == p_limb ? 1 : 0 },
107 { C::to_radix_limb_p_diff, limb_p_diff },
111 if (is_unsafe_limb) {
120 trace.invert_columns({ { C::to_radix_safety_diff_inverse, C::to_radix_rem_inverse } });
146 for (
const auto&
event : events) {
148 const uint32_t num_limbs =
event.num_limbs;
149 bool num_limbs_is_zero = num_limbs == 0;
150 bool value_is_zero =
event.value ==
FF(0);
153 uint64_t
dst_addr =
static_cast<uint64_t
>(
event.dst_addr);
154 uint64_t write_addr_upper_bound =
dst_addr + num_limbs;
158 bool invalid_radix = (
event.radix < 2 ||
event.radix > 256);
161 bool radix_eq_2 =
event.radix == 2;
162 bool invalid_bitwise_radix =
event.is_output_bits && !radix_eq_2;
165 bool invalid_num_limbs = num_limbs_is_zero && !value_is_zero;
170 { C::to_radix_mem_sel, 1 },
171 { C::to_radix_mem_start, 1 },
174 { C::to_radix_mem_execution_clk,
event.execution_clk },
175 { C::to_radix_mem_space_id,
event.space_id },
176 { C::to_radix_mem_dst_addr,
dst_addr },
177 { C::to_radix_mem_value_to_decompose,
event.value },
178 { C::to_radix_mem_radix,
event.radix },
179 { C::to_radix_mem_num_limbs, num_limbs },
180 { C::to_radix_mem_is_output_bits,
event.is_output_bits ? 1 : 0 },
182 { C::to_radix_mem_max_mem_size,
static_cast<uint64_t
>(
AVM_MEMORY_SIZE) },
183 { C::to_radix_mem_write_addr_upper_bound, write_addr_upper_bound },
184 { C::to_radix_mem_two, 2 },
185 { C::to_radix_mem_two_five_six, 256 },
186 { C::to_radix_mem_sel_num_limbs_is_zero, num_limbs_is_zero ? 1 : 0 },
187 { C::to_radix_mem_num_limbs_inv, num_limbs },
188 { C::to_radix_mem_sel_value_is_zero, value_is_zero ? 1 : 0 },
189 { C::to_radix_mem_value_inv,
event.value },
190 { C::to_radix_mem_sel_radix_eq_2, radix_eq_2 ? 1 : 0 },
191 { C::to_radix_mem_radix_min_two_inv,
FF(
event.radix) -
FF(2) },
195 if (write_out_of_range || invalid_radix || invalid_bitwise_radix || invalid_num_limbs) {
198 { C::to_radix_mem_last, 1 },
199 { C::to_radix_mem_input_validation_error, 1 },
200 { C::to_radix_mem_err, 1 },
201 { C::to_radix_mem_sel_dst_out_of_range_err, write_out_of_range ? 1 : 0 },
202 { C::to_radix_mem_sel_radix_lt_2_err,
event.radix < 2 ? 1 : 0 },
203 { C::to_radix_mem_sel_radix_gt_256_err,
event.radix > 256 ? 1 : 0 },
204 { C::to_radix_mem_sel_invalid_bitwise_radix, invalid_bitwise_radix ? 1 : 0 },
211 BB_ASSERT(
event.limbs.size() ==
static_cast<size_t>(num_limbs),
"Number of limbs does not match");
216 if (num_limbs == 0) {
219 { C::to_radix_mem_last, 1 },
230 std::vector<bool> found(num_limbs,
false);
231 for (
size_t i = 0; i < num_limbs; ++i) {
233 size_t reverse_index =
event.limbs.size() - i - 1;
234 FF limb_value =
event.limbs[reverse_index].as_ff();
235 acc += power * limb_value;
236 power *=
event.radix;
237 found[reverse_index] = acc ==
event.value;
244 const bool truncation_error = (num_limbs != 0) && !found.at(0);
248 if (truncation_error) {
251 { C::to_radix_mem_last, 1 },
252 { C::to_radix_mem_err, 1 },
254 { C::to_radix_mem_sel_should_decompose, 1 },
255 { C::to_radix_mem_limb_index_to_lookup, num_limbs - 1 },
256 { C::to_radix_mem_limb_value,
event.limbs[0].as_ff() },
264 uint32_t remaining_limbs = num_limbs;
270 for (uint32_t i = 0; i < num_limbs; ++i) {
272 bool last = i == (num_limbs - 1);
285 { C::to_radix_mem_sel, 1 },
286 { C::to_radix_mem_num_limbs, remaining_limbs },
287 { C::to_radix_mem_num_limbs_minus_one_inv,
288 FF(remaining_limbs - 1) },
289 { C::to_radix_mem_last, last ? 1 : 0 },
291 { C::to_radix_mem_sel_should_decompose, 1 },
292 { C::to_radix_mem_value_to_decompose,
event.value },
293 { C::to_radix_mem_limb_index_to_lookup, remaining_limbs - 1 },
294 { C::to_radix_mem_radix,
event.radix },
295 { C::to_radix_mem_limb_value, limb_value.
as_ff() },
296 { C::to_radix_mem_value_found, found.at(i) ? 1 : 0 },
298 { C::to_radix_mem_sel_should_write_mem, 1 },
299 { C::to_radix_mem_execution_clk,
event.execution_clk },
300 { C::to_radix_mem_space_id,
event.space_id },
301 { C::to_radix_mem_dst_addr,
dst_addr },
302 { C::to_radix_mem_output_tag,
static_cast<uint8_t
>(limb_value.
get_tag()) },
303 { C::to_radix_mem_is_output_bits,
event.is_output_bits ? 1 : 0 },
314 trace.invert_columns({ {
315 C::to_radix_mem_num_limbs_inv,
316 C::to_radix_mem_value_inv,
317 C::to_radix_mem_num_limbs_minus_one_inv,
318 C::to_radix_mem_radix_min_two_inv,