34 for (
const auto&
event : events) {
36 const uint32_t radix =
event.radix;
37 BB_ASSERT(radix >= 2 && radix <= 256,
"Invalid radix");
38 const auto& p_limbs = p_limbs_per_radix[
static_cast<size_t>(radix)];
44 const uint32_t safe_limbs =
static_cast<uint32_t
>(p_limbs.size()) - 1;
49 bool acc_under_p =
false;
51 for (uint32_t i = 0; i <
event.limbs.size(); ++i) {
52 const bool is_padding = i > safe_limbs;
53 const uint8_t limb =
event.limbs[i];
54 const uint8_t p_limb = is_padding ? 0 : p_limbs[
static_cast<size_t>(i)];
58 acc_under_p = limb < p_limb;
65 limb_p_diff = limb - p_limb - 1;
66 }
else if (limb < p_limb) {
67 limb_p_diff = p_limb - limb - 1;
70 bool is_unsafe_limb = i == safe_limbs;
71 FF safety_diff =
FF(i) -
FF(safe_limbs);
73 acc += power *
FF(limb);
78 bool end = i == (
event.limbs.size() - 1);
82 { C::to_radix_sel, 1 },
83 { C::to_radix_value,
value },
84 { C::to_radix_radix, radix },
85 { C::to_radix_limb_index, i },
86 { C::to_radix_limb, limb },
87 { C::to_radix_start, i == 0 ? 1 : 0 },
88 { C::to_radix_end, end ? 1 : 0 },
89 { C::to_radix_power, power },
90 { C::to_radix_not_padding_limb, !is_padding ? 1 : 0 },
91 { C::to_radix_acc, acc },
92 { C::to_radix_found, found ? 1 : 0 },
93 { C::to_radix_limb_radix_diff, radix - limb - 1 },
94 { C::to_radix_rem_inverse, rem },
95 { C::to_radix_safe_limbs, safe_limbs },
96 { C::to_radix_is_unsafe_limb, is_unsafe_limb ? 1 : 0 },
97 { C::to_radix_safety_diff_inverse, safety_diff },
98 { C::to_radix_p_limb, p_limb },
99 { C::to_radix_acc_under_p, acc_under_p ? 1 : 0 },
100 { C::to_radix_limb_lt_p, limb < p_limb ? 1 : 0 },
101 { C::to_radix_limb_eq_p, limb == p_limb ? 1 : 0 },
102 { C::to_radix_limb_p_diff, limb_p_diff },
106 if (is_unsafe_limb) {
115 trace.invert_columns({ { C::to_radix_safety_diff_inverse, C::to_radix_rem_inverse } });
130 for (
const auto&
event : events) {
132 const uint32_t num_limbs =
event.num_limbs;
133 uint8_t num_limbs_is_zero = num_limbs == 0 ? 1 : 0;
134 uint8_t value_is_zero =
event.value ==
FF(0) ? 1 : 0;
137 uint64_t
dst_addr =
static_cast<uint64_t
>(
event.dst_addr);
138 uint64_t write_addr_upper_bound =
dst_addr + num_limbs;
142 bool invalid_radix = (
event.radix < 2 ||
event.radix > 256);
145 bool radix_eq_2 =
event.radix == 2;
146 bool invalid_bitwise_radix =
event.is_output_bits && !radix_eq_2;
149 bool invalid_num_limbs = num_limbs == 0 && !(
event.value ==
FF(0));
154 { C::to_radix_mem_sel, 1 },
155 { C::to_radix_mem_start, 1 },
157 { C::to_radix_mem_execution_clk,
event.execution_clk },
158 { C::to_radix_mem_space_id,
event.space_id },
160 { C::to_radix_mem_dst_addr,
dst_addr },
161 { C::to_radix_mem_value_to_decompose,
event.value },
162 { C::to_radix_mem_radix,
event.radix },
163 { C::to_radix_mem_num_limbs, num_limbs },
164 { C::to_radix_mem_is_output_bits,
event.is_output_bits ? 1 : 0 },
166 { C::to_radix_mem_max_mem_size,
static_cast<uint64_t
>(
AVM_MEMORY_SIZE) },
167 { C::to_radix_mem_write_addr_upper_bound, write_addr_upper_bound },
168 { C::to_radix_mem_two, 2 },
169 { C::to_radix_mem_two_five_six, 256 },
170 { C::to_radix_mem_sel_num_limbs_is_zero, num_limbs_is_zero },
171 { C::to_radix_mem_num_limbs_inv, num_limbs },
172 { C::to_radix_mem_sel_value_is_zero, value_is_zero },
173 { C::to_radix_mem_value_inv,
event.value },
174 { C::to_radix_mem_sel_radix_eq_2, radix_eq_2 ? 1 : 0 },
175 { C::to_radix_mem_radix_min_two_inv,
FF(
event.radix) -
FF(2) },
179 if (write_out_of_range || invalid_radix || invalid_bitwise_radix || invalid_num_limbs) {
182 { C::to_radix_mem_last, 1 },
183 { C::to_radix_mem_input_validation_error, 1 },
184 { C::to_radix_mem_err, 1 },
185 { C::to_radix_mem_sel_dst_out_of_range_err, write_out_of_range ? 1 : 0 },
186 { C::to_radix_mem_sel_radix_lt_2_err,
event.radix < 2 ? 1 : 0 },
187 { C::to_radix_mem_sel_radix_gt_256_err,
event.radix > 256 ? 1 : 0 },
188 { C::to_radix_mem_sel_invalid_bitwise_radix, invalid_bitwise_radix ? 1 : 0 },
189 { C::to_radix_mem_sel_invalid_num_limbs_err, invalid_num_limbs ? 1 : 0 },
196 BB_ASSERT(
event.limbs.size() ==
static_cast<size_t>(num_limbs),
"Number of limbs does not match");
201 if (num_limbs == 0) {
204 { C::to_radix_mem_last, 1 },
215 std::vector<bool> found(num_limbs,
false);
216 for (
size_t i = 0; i < num_limbs; ++i) {
218 size_t reverse_index =
event.limbs.size() - i - 1;
219 FF limb_value =
event.limbs[reverse_index].as_ff();
220 acc += power * limb_value;
221 power *=
event.radix;
222 found[reverse_index] = acc ==
event.value;
229 const bool truncation_error = (num_limbs != 0) && !found.at(0);
233 if (truncation_error) {
236 { C::to_radix_mem_last, 1 },
237 { C::to_radix_mem_err, 1 },
238 { C::to_radix_mem_sel_truncation_error, 1 },
240 { C::to_radix_mem_sel_should_decompose, 1 },
241 { C::to_radix_mem_limb_index_to_lookup, num_limbs - 1 },
242 { C::to_radix_mem_limb_value,
event.limbs[0].as_ff() },
243 { C::to_radix_mem_value_found, 0 },
250 uint32_t remaining_limbs = num_limbs;
256 for (uint32_t i = 0; i < num_limbs; ++i) {
258 bool last = i == (num_limbs - 1);
268 { C::to_radix_mem_sel, 1 },
269 { C::to_radix_mem_num_limbs, remaining_limbs },
270 { C::to_radix_mem_num_limbs_minus_one_inv,
271 FF(remaining_limbs - 1) },
272 { C::to_radix_mem_last, last ? 1 : 0 },
274 { C::to_radix_mem_sel_should_decompose, 1 },
275 { C::to_radix_mem_value_to_decompose,
event.value },
276 { C::to_radix_mem_limb_index_to_lookup, remaining_limbs - 1 },
277 { C::to_radix_mem_radix,
event.radix },
278 { C::to_radix_mem_limb_value, limb_value.
as_ff() },
279 { C::to_radix_mem_value_found, found.at(i) ? 1 : 0 },
281 { C::to_radix_mem_sel_should_write_mem, 1 },
282 { C::to_radix_mem_execution_clk,
event.execution_clk },
283 { C::to_radix_mem_space_id,
event.space_id },
284 { C::to_radix_mem_dst_addr,
dst_addr },
285 { C::to_radix_mem_output_tag,
static_cast<uint8_t
>(limb_value.
get_tag()) },
286 { C::to_radix_mem_is_output_bits,
event.is_output_bits ? 1 : 0 },
297 trace.invert_columns({ {
298 C::to_radix_mem_num_limbs_inv,
299 C::to_radix_mem_value_inv,
300 C::to_radix_mem_num_limbs_minus_one_inv,
301 C::to_radix_mem_radix_min_two_inv,