26 for (
const auto&
event : events) {
28 uint32_t radix =
event.radix;
29 BB_ASSERT(radix >= 2 && radix <= 256,
"Invalid radix");
30 size_t radix_index =
static_cast<size_t>(radix);
31 uint32_t safe_limbs =
static_cast<uint32_t
>(p_limbs_per_radix[radix_index].size()) - 1;
36 bool acc_under_p =
false;
38 for (uint32_t i = 0; i <
event.limbs.size(); ++i) {
39 bool is_padding = i > safe_limbs;
40 uint8_t limb =
event.limbs[i];
41 uint8_t p_limb = is_padding ? 0 : p_limbs_per_radix[radix_index][
static_cast<size_t>(i)];
44 acc_under_p = limb < p_limb;
46 FF limb_p_diff = limb == p_limb ? 0 : limb > p_limb ? limb - p_limb - 1 : p_limb - limb - 1;
48 bool is_unsafe_limb = i == safe_limbs;
49 FF safety_diff =
FF(i) -
FF(safe_limbs);
51 acc += exponent * limb;
56 bool end = i == (
event.limbs.size() - 1);
60 { C::to_radix_sel, 1 },
61 { C::to_radix_value,
value },
62 { C::to_radix_radix, radix },
63 { C::to_radix_limb_index, i },
64 { C::to_radix_limb, limb },
65 { C::to_radix_start, i == 0 },
66 { C::to_radix_end, end },
67 { C::to_radix_not_end, !end },
68 { C::to_radix_exponent, exponent },
69 { C::to_radix_not_padding_limb, !is_padding },
70 { C::to_radix_acc, acc },
71 { C::to_radix_found, found },
72 { C::to_radix_limb_radix_diff, radix - 1 - limb },
73 { C::to_radix_rem_inverse, rem },
74 { C::to_radix_safe_limbs, safe_limbs },
75 { C::to_radix_is_unsafe_limb, is_unsafe_limb },
76 { C::to_radix_safety_diff_inverse, safety_diff },
77 { C::to_radix_p_limb, p_limb },
78 { C::to_radix_acc_under_p, acc_under_p },
79 { C::to_radix_limb_lt_p, limb < p_limb },
80 { C::to_radix_limb_eq_p, limb == p_limb },
81 { C::to_radix_limb_p_diff, limb_p_diff },
93 trace.invert_columns({ { C::to_radix_safety_diff_inverse, C::to_radix_rem_inverse } });
102 for (
const auto&
event : events) {
104 uint8_t num_limbs_is_zero =
event.num_limbs == 0 ? 1 : 0;
105 FF num_limbs_inv =
event.num_limbs == 0 ?
FF(0) :
FF(
event.num_limbs);
106 uint8_t value_is_zero =
event.value ==
FF(0) ? 1 : 0;
107 FF value_inv =
event.value ==
FF(0) ?
FF(0) :
event.value;
110 uint64_t
dst_addr =
static_cast<uint64_t
>(
event.dst_addr);
111 uint64_t write_addr_upper_bound =
dst_addr +
event.num_limbs;
115 bool invalid_radix = (
event.radix < 2 ||
event.radix > 256);
116 bool invalid_bitwise_radix =
event.is_output_bits &&
event.radix != 2;
119 bool invalid_num_limbs =
event.num_limbs == 0 && !(
event.value ==
FF(0));
124 { C::to_radix_mem_sel, 1 },
125 { C::to_radix_mem_start, 1 },
127 { C::to_radix_mem_execution_clk,
event.execution_clk },
128 { C::to_radix_mem_space_id,
event.space_id },
129 { C::to_radix_mem_dst_addr,
dst_addr },
130 { C::to_radix_mem_value_to_decompose,
event.value },
131 { C::to_radix_mem_radix,
event.radix },
132 { C::to_radix_mem_num_limbs,
event.num_limbs },
133 { C::to_radix_mem_is_output_bits,
event.is_output_bits ? 1 : 0 },
135 { C::to_radix_mem_max_mem_size,
static_cast<uint64_t
>(
AVM_MEMORY_SIZE) },
136 { C::to_radix_mem_write_addr_upper_bound, write_addr_upper_bound },
137 { C::to_radix_mem_two, 2 },
138 { C::to_radix_mem_two_five_six, 256 },
139 { C::to_radix_mem_sel_num_limbs_is_zero, num_limbs_is_zero },
140 { C::to_radix_mem_num_limbs_inv, num_limbs_inv },
141 { C::to_radix_mem_sel_value_is_zero, value_is_zero },
142 { C::to_radix_mem_value_inv, value_inv },
146 if (write_out_of_range || invalid_radix || invalid_bitwise_radix || invalid_num_limbs) {
149 { C::to_radix_mem_last, 1 },
150 { C::to_radix_mem_input_validation_error, 1 },
151 { C::to_radix_mem_err, 1 },
152 { C::to_radix_mem_sel_dst_out_of_range_err, write_out_of_range },
153 { C::to_radix_mem_sel_radix_lt_2_err,
event.radix < 2 },
154 { C::to_radix_mem_sel_radix_gt_256_err,
event.radix > 256 },
155 { C::to_radix_mem_sel_invalid_bitwise_radix, invalid_bitwise_radix ? 1 : 0 },
156 { C::to_radix_mem_sel_invalid_num_limbs_err, invalid_num_limbs ? 1 : 0 },
167 std::vector<bool> found(
event.limbs.size(),
false);
168 for (
size_t i = 0; i <
event.limbs.size(); ++i) {
170 size_t reverse_index =
event.limbs.size() - i - 1;
171 FF limb_value =
event.limbs[reverse_index].as_ff();
172 acc += exponent * limb_value;
173 exponent *=
event.radix;
174 found[reverse_index] = acc ==
event.value;
178 if (
event.num_limbs == 0) {
181 { C::to_radix_mem_last, 1 },
188 bool truncation_error =
event.num_limbs != 0 && !found.at(0);
190 if (truncation_error) {
193 { C::to_radix_mem_last, 1 },
194 { C::to_radix_mem_err, 1 },
195 { C::to_radix_mem_sel_truncation_error, 1 },
197 { C::to_radix_mem_sel_should_decompose, 1 },
198 { C::to_radix_mem_limb_index_to_lookup,
event.num_limbs - 1 },
199 { C::to_radix_mem_limb_value,
event.limbs.at(0).as_ff() },
200 { C::to_radix_mem_value_found, 0 },
207 uint32_t remaining_limbs =
static_cast<uint32_t
>(
event.num_limbs);
210 for (uint32_t i = 0; i <
event.num_limbs; ++i) {
212 bool last = i == (
event.num_limbs - 1);
216 { C::to_radix_mem_sel, 1 },
217 { C::to_radix_mem_num_limbs, remaining_limbs },
218 { C::to_radix_mem_num_limbs_minus_one_inv,
219 remaining_limbs - 1 == 0 ? 0 :
FF(remaining_limbs - 1) },
220 { C::to_radix_mem_last, last ? 1 : 0 },
222 { C::to_radix_mem_sel_should_decompose, 1 },
223 { C::to_radix_mem_value_to_decompose,
event.value },
224 { C::to_radix_mem_limb_index_to_lookup, remaining_limbs - 1 },
225 { C::to_radix_mem_radix,
event.radix },
226 { C::to_radix_mem_limb_value, limb_value.
as_ff() },
227 { C::to_radix_mem_value_found, found.at(i) ? 1 : 0 },
229 { C::to_radix_mem_sel_should_write_mem, 1 },
230 { C::to_radix_mem_execution_clk,
event.execution_clk },
231 { C::to_radix_mem_space_id,
event.space_id },
232 { C::to_radix_mem_dst_addr,
dst_addr },
233 { C::to_radix_mem_output_tag,
static_cast<uint8_t
>(limb_value.
get_tag()) },
234 { C::to_radix_mem_is_output_bits,
event.is_output_bits ? 1 : 0 },
245 trace.invert_columns(
246 { { C::to_radix_mem_num_limbs_inv, C::to_radix_mem_value_inv, C::to_radix_mem_num_limbs_minus_one_inv } });