Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
to_radix.cpp
Go to the documentation of this file.
2
3#include <algorithm>
4
9
10namespace bb::avm2::simulation {
11
23 uint32_t num_limbs,
24 uint32_t radix)
25{
26 BB_ASSERT_LTE(radix, static_cast<decltype(radix)>(256), "Radix is greater than 256");
27 BB_ASSERT_GTE(radix, static_cast<decltype(radix)>(2), "Radix is less than 2");
28
29 std::vector<uint8_t> limbs;
30 uint32_t num_p_limbs = static_cast<uint32_t>(get_p_limbs_per_radix_size(radix));
31 limbs.reserve(std::max(num_limbs, num_p_limbs));
32
33 uint256_t value_integer = static_cast<uint256_t>(value);
34 while (value_integer != 0) {
35 auto [quotient, remainder] = value_integer.divmod(static_cast<uint64_t>(radix));
36 limbs.push_back(static_cast<uint8_t>(remainder)); // Cast is fine by the precondition that radix <= 256.
37 value_integer = quotient;
38 }
39
40 if (num_limbs > limbs.size()) {
41 limbs.insert(limbs.end(), num_limbs - limbs.size(), 0);
42 }
43
44 // The event should never have less limbs than the necessary to perform the decomposition
46 .value = value,
47 .radix = radix,
48 .limbs = limbs,
49 });
50
51 bool truncated = num_limbs < limbs.size();
52 if (truncated) {
53 limbs.erase(limbs.begin() + num_limbs, limbs.end());
54 }
55
56 return { limbs, truncated };
57}
58
67std::pair<std::vector<bool>, /* truncated */ bool> ToRadix::to_le_bits(const FF& value, uint32_t num_limbs)
68{
69 const auto [limbs, truncated] = to_le_radix(value, num_limbs, 2);
70 std::vector<bool> bits;
71 bits.reserve(limbs.size());
72
73 for (uint8_t val : limbs) {
74 bits.push_back(val != 0); // Convert nonzero values to `true`, zero to `false`
75 };
76
77 return { bits, truncated };
78}
79
103 const FF& value,
104 uint32_t radix,
105 uint32_t num_limbs,
106 bool is_output_bits, // Decides if output is U1 or U8
108{
109
110 uint32_t execution_clk = execution_id_manager.get_execution_id();
111 uint16_t space_id = memory.get_space_id();
112
113 // Error handling - check that the maximum write address does not exceed the highest memory address
114 // This subtrace writes in the range { dst_addr, dst_addr + 1, ..., dst_addr + num_limbs - 1 }
115 uint64_t write_addr_upper_bound = static_cast<uint64_t>(dst_addr) + num_limbs;
116 bool dst_out_of_range = gt.gt(write_addr_upper_bound, AVM_MEMORY_SIZE);
117
118 // Error handling - check that the radix value is within the valid range
119 // The valid range is [2, 256]. Therefore, the radix is invalid if (2 > radix) or (radix > 256)
120 // We need to perform both checks explicitly since that is what the circuit would do
121 bool radix_is_lt_2 = gt.gt(2, radix);
122 bool radix_is_gt_256 = gt.gt(radix, 256);
123
124 // Error handling - check that if is_output_bits is true, the radix has to be 2
125 bool invalid_bitwise_radix = is_output_bits && (radix != 2);
126 // Error handling - if num_limbs is zero, value needs to be zero
127 bool invalid_num_limbs = (num_limbs == 0) && (!value.is_zero());
128
129 ToRadixMemoryEvent event = {
130 .execution_clk = execution_clk,
131 .space_id = space_id,
132 .num_limbs = num_limbs,
133 .dst_addr = dst_addr,
134 .value = value,
135 .radix = radix,
136 .is_output_bits = is_output_bits,
137 .limbs = {},
138 };
139
140 if (dst_out_of_range || radix_is_lt_2 || radix_is_gt_256 || invalid_bitwise_radix || invalid_num_limbs) {
142 throw ToRadixException("Error during BE conversion: Invalid parameters for ToRadix");
143 }
144
145 bool truncated = false;
146
147 if (num_limbs > 0) {
148 event.limbs.reserve(num_limbs);
149 if (is_output_bits) {
150 const auto [limbs, truncated_decomposition] = to_le_bits(value, num_limbs);
151 truncated = truncated_decomposition;
152 std::ranges::for_each(limbs.rbegin(), limbs.rend(), [&](bool bit) {
153 event.limbs.push_back(MemoryValue::from<uint1_t>(bit));
154 });
155 } else {
156 const auto [limbs, truncated_decomposition] = to_le_radix(value, num_limbs, radix);
157 truncated = truncated_decomposition;
158 std::ranges::for_each(limbs.rbegin(), limbs.rend(), [&](uint8_t limb) {
159 event.limbs.push_back(MemoryValue::from<uint8_t>(limb));
160 });
161 }
162 }
163
164 if (truncated) {
166 throw ToRadixException("Error during BE conversion: Truncation error");
167 }
168
169 // If we get to this point, we are error free.
170 for (uint32_t i = 0; i < num_limbs; i++) {
171 memory.set(dst_addr + i, event.limbs[i]);
172 }
173
175}
176
177} // namespace bb::avm2::simulation
#define BB_ASSERT_GTE(left, right,...)
Definition assert.hpp:128
#define BB_ASSERT_LTE(left, right,...)
Definition assert.hpp:158
#define AVM_MEMORY_SIZE
virtual uint32_t get_execution_id() const =0
EventEmitterInterface< ToRadixMemoryEvent > & memory_events
Definition to_radix.hpp:45
EventEmitterInterface< ToRadixEvent > & events
Definition to_radix.hpp:44
std::pair< std::vector< bool >, bool > to_le_bits(const FF &value, uint32_t num_limbs) override
Performs a little endian radix decomposition of a field element into bits. This emits a ToRadixEvent.
Definition to_radix.cpp:67
std::pair< std::vector< uint8_t >, bool > to_le_radix(const FF &value, uint32_t num_limbs, uint32_t radix) override
Performs a little endian radix decomposition of a field element into limbs. This emits a ToRadixEvent...
Definition to_radix.cpp:22
void to_be_radix(MemoryInterface &memory, const FF &value, uint32_t radix, uint32_t num_limbs, bool is_output_bits, MemoryAddress dst_addr) override
Performs a big endian radix decomposition of a field element into limbs. This directly emits a ToRadi...
Definition to_radix.cpp:102
ExecutionIdManagerInterface & execution_id_manager
Definition to_radix.hpp:42
constexpr std::pair< uint256_t, uint256_t > divmod(const uint256_t &b) const
uint32_t dst_addr
AVM range check gadget for witness generation.
size_t get_p_limbs_per_radix_size(size_t radix)
Gets the number of limbs that the modulus, p, decomposes into for a given radix.
Definition to_radix.cpp:75
AvmFlavorSettings::FF FF
Definition field.hpp:10
uint32_t MemoryAddress
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
simulation::PublicDataTreeReadWriteEvent event
BB_INLINE constexpr bool is_zero() const noexcept