25 for (
const auto&
event : events) {
27 uint32_t radix =
event.radix;
28 size_t radix_index =
static_cast<size_t>(radix);
29 uint32_t safe_limbs =
static_cast<uint32_t
>(p_limbs_per_radix[radix_index].size()) - 1;
34 bool acc_under_p =
false;
36 for (uint32_t i = 0; i <
event.limbs.size(); ++i) {
37 bool is_padding = i > safe_limbs;
38 uint8_t limb =
event.limbs[i];
39 uint8_t p_limb = is_padding ? 0 : p_limbs_per_radix[radix_index][
static_cast<size_t>(i)];
42 acc_under_p = limb < p_limb;
44 FF limb_p_diff = limb == p_limb ? 0 : limb > p_limb ? limb - p_limb - 1 : p_limb - limb - 1;
46 bool is_unsafe_limb = i == safe_limbs;
47 FF safety_diff =
FF(i) -
FF(safe_limbs);
49 acc += exponent * limb;
54 bool end = i == (
event.limbs.size() - 1);
58 { C::to_radix_sel, 1 },
59 { C::to_radix_value,
value },
60 { C::to_radix_radix, radix },
61 { C::to_radix_limb_index, i },
62 { C::to_radix_limb, limb },
63 { C::to_radix_start, i == 0 },
64 { C::to_radix_end, end },
65 { C::to_radix_not_end, !end },
66 { C::to_radix_exponent, exponent },
67 { C::to_radix_not_padding_limb, !is_padding },
68 { C::to_radix_acc, acc },
69 { C::to_radix_found, found },
70 { C::to_radix_limb_radix_diff, radix - 1 - limb },
71 { C::to_radix_rem_inverse, rem },
72 { C::to_radix_safe_limbs, safe_limbs },
73 { C::to_radix_is_unsafe_limb, is_unsafe_limb },
74 { C::to_radix_safety_diff_inverse, safety_diff },
75 { C::to_radix_p_limb, p_limb },
76 { C::to_radix_acc_under_p, acc_under_p },
77 { C::to_radix_limb_lt_p, limb < p_limb },
78 { C::to_radix_limb_eq_p, limb == p_limb },
79 { C::to_radix_limb_p_diff, limb_p_diff },
91 trace.invert_columns({ { C::to_radix_safety_diff_inverse, C::to_radix_rem_inverse } });
100 for (
const auto&
event : events) {
102 uint8_t num_limbs_is_zero =
event.num_limbs == 0 ? 1 : 0;
103 FF num_limbs_inv =
event.num_limbs == 0 ?
FF(0) :
FF(
event.num_limbs);
104 uint8_t value_is_zero =
event.value ==
FF(0) ? 1 : 0;
105 FF value_inv =
event.value ==
FF(0) ?
FF(0) :
event.value;
108 uint64_t
dst_addr =
static_cast<uint64_t
>(
event.dst_addr);
109 uint64_t max_write_addr =
dst_addr +
event.num_limbs - 1;
113 bool invalid_radix = (
event.radix < 2 ||
event.radix > 256);
114 bool invalid_bitwise_radix =
event.is_output_bits &&
event.radix != 2;
117 bool invalid_num_limbs =
event.num_limbs == 0 && !(
event.value ==
FF(0));
122 { C::to_radix_mem_sel, 1 },
123 { C::to_radix_mem_start, 1 },
125 { C::to_radix_mem_execution_clk,
event.execution_clk },
126 { C::to_radix_mem_space_id,
event.space_id },
127 { C::to_radix_mem_dst_addr,
dst_addr },
128 { C::to_radix_mem_value_to_decompose,
event.value },
129 { C::to_radix_mem_radix,
event.radix },
130 { C::to_radix_mem_num_limbs,
event.num_limbs },
131 { C::to_radix_mem_is_output_bits,
event.is_output_bits ? 1 : 0 },
134 { C::to_radix_mem_max_write_addr, max_write_addr },
135 { C::to_radix_mem_two, 2 },
136 { C::to_radix_mem_two_five_six, 256 },
137 { C::to_radix_mem_sel_num_limbs_is_zero, num_limbs_is_zero },
138 { C::to_radix_mem_num_limbs_inv, num_limbs_inv },
139 { C::to_radix_mem_sel_value_is_zero, value_is_zero },
140 { C::to_radix_mem_value_inv, value_inv },
144 if (write_out_of_range || invalid_radix || invalid_bitwise_radix || invalid_num_limbs) {
147 { C::to_radix_mem_last, 1 },
148 { C::to_radix_mem_input_validation_error, 1 },
149 { C::to_radix_mem_err, 1 },
150 { C::to_radix_mem_sel_dst_out_of_range_err, write_out_of_range },
151 { C::to_radix_mem_sel_radix_lt_2_err,
event.radix < 2 },
152 { C::to_radix_mem_sel_radix_gt_256_err,
event.radix > 256 },
153 { C::to_radix_mem_sel_invalid_bitwise_radix, invalid_bitwise_radix ? 1 : 0 },
154 { C::to_radix_mem_sel_invalid_num_limbs_err, invalid_num_limbs ? 1 : 0 },
165 std::vector<bool> found(
event.limbs.size(),
false);
166 for (
size_t i = 0; i <
event.limbs.size(); ++i) {
168 size_t reverse_index =
event.limbs.size() - i - 1;
169 FF limb_value =
event.limbs[reverse_index].as_ff();
170 acc += exponent * limb_value;
171 exponent *=
event.radix;
172 found[reverse_index] = acc ==
event.value;
176 if (
event.num_limbs == 0) {
179 { C::to_radix_mem_last, 1 },
186 bool truncation_error =
event.num_limbs != 0 && !found.at(0);
188 if (truncation_error) {
191 { C::to_radix_mem_last, 1 },
192 { C::to_radix_mem_err, 1 },
193 { C::to_radix_mem_sel_truncation_error, 1 },
195 { C::to_radix_mem_sel_should_decompose, 1 },
196 { C::to_radix_mem_limb_index_to_lookup,
event.num_limbs - 1 },
197 { C::to_radix_mem_limb_value,
event.limbs.at(0).as_ff() },
198 { C::to_radix_mem_value_found, 0 },
205 uint32_t remaining_limbs =
static_cast<uint32_t
>(
event.num_limbs);
208 for (uint32_t i = 0; i <
event.num_limbs; ++i) {
210 bool last = i == (
event.num_limbs - 1);
214 { C::to_radix_mem_sel, 1 },
215 { C::to_radix_mem_num_limbs, remaining_limbs },
216 { C::to_radix_mem_num_limbs_minus_one_inv,
217 remaining_limbs - 1 == 0 ? 0 :
FF(remaining_limbs - 1) },
218 { C::to_radix_mem_last, last ? 1 : 0 },
220 { C::to_radix_mem_sel_should_decompose, 1 },
221 { C::to_radix_mem_value_to_decompose,
event.value },
222 { C::to_radix_mem_limb_index_to_lookup, remaining_limbs - 1 },
223 { C::to_radix_mem_radix,
event.radix },
224 { C::to_radix_mem_limb_value, limb_value.
as_ff() },
225 { C::to_radix_mem_value_found, found.at(i) ? 1 : 0 },
227 { C::to_radix_mem_sel_should_write_mem, 1 },
228 { C::to_radix_mem_execution_clk,
event.execution_clk },
229 { C::to_radix_mem_space_id,
event.space_id },
230 { C::to_radix_mem_dst_addr,
dst_addr },
231 { C::to_radix_mem_output_tag,
static_cast<uint8_t
>(limb_value.
get_tag()) },
232 { C::to_radix_mem_is_output_bits,
event.is_output_bits ? 1 : 0 },
243 trace.invert_columns(
244 { { C::to_radix_mem_num_limbs_inv, C::to_radix_mem_value_inv, C::to_radix_mem_num_limbs_minus_one_inv } });