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#include <cstdint>
5#include <stdexcept>
6#include <vector>
7
11
12namespace bb::avm2::simulation {
13
15 uint32_t num_limbs,
16 uint32_t radix)
17{
18 std::vector<uint8_t> limbs;
19 uint32_t num_p_limbs = static_cast<uint32_t>(get_p_limbs_per_radix_size(radix));
20 limbs.reserve(std::max(num_limbs, num_p_limbs));
21
22 uint256_t value_integer = static_cast<uint256_t>(value);
23 while (value_integer != 0) {
24 auto [quotient, remainder] = value_integer.divmod(radix);
25 limbs.push_back(static_cast<uint8_t>(remainder));
26 value_integer = quotient;
27 }
28
29 if (num_limbs > limbs.size()) {
30 limbs.insert(limbs.end(), num_limbs - limbs.size(), 0);
31 }
32
33 // The event should never have less limbs than the necessary to perform the decomposition
35 .value = value,
36 .radix = radix,
37 .limbs = limbs,
38 });
39
40 bool truncated = num_limbs < limbs.size();
41 if (truncated) {
42 limbs.erase(limbs.begin() + num_limbs, limbs.end());
43 }
44
45 return { limbs, truncated };
46}
47
48std::pair<std::vector<bool>, /* truncated */ bool> ToRadix::to_le_bits(const FF& value, uint32_t num_limbs)
49{
50 const auto [limbs, truncated] = to_le_radix(value, num_limbs, 2);
51 std::vector<bool> bits(limbs.size());
52
53 std::transform(limbs.begin(), limbs.end(), bits.begin(), [](uint8_t val) {
54 return val != 0; // Convert nonzero values to `true`, zero to `false`
55 });
56
57 return { bits, truncated };
58}
59
61 const FF& value,
62 uint32_t radix,
63 uint32_t num_limbs,
64 bool is_output_bits, // Decides if output is U1 or U8
66{
67
68 uint32_t execution_clk = execution_id_manager.get_execution_id();
69 uint16_t space_id = memory.get_space_id();
70
71 // todo(ilyas): there must be a nicer way to do this in the simulator. See if it's fine to provide
72 // a hierarchy of errors so that we can throw on the first error we encounter
73
74 // Error handling - check that the maximum write address does not exceed the highest memory address
75 // This subtrace writes in the range { dst_addr, dst_addr + 1, ..., dst_addr + num_limbs - 1 }
76 uint64_t max_write_address = static_cast<uint64_t>(dst_addr) + num_limbs - 1;
77 bool dst_out_of_range = gt.gt(max_write_address, AVM_HIGHEST_MEM_ADDRESS);
78
79 // Error handling - check that the radix value is within the valid range
80 // The valid range is [2, 256]. Therefore, the radix is invalid if (2 > radix) or (radix > 256)
81 // We need to perform both checks explicitly since that is what the circuit would do
82 bool radix_is_lt_2 = gt.gt(2, radix);
83 bool radix_is_gt_256 = gt.gt(radix, 256);
84
85 // Error handling - check that if is_output_bits is true, the radix has to be 2
86 bool invalid_bitwise_radix = is_output_bits && (radix != 2);
87 // Error handling - if num_limbs is zero, value needs to be zero
88 bool invalid_num_limbs = (num_limbs == 0) && (value != FF(0));
89
90 ToRadixMemoryEvent event = {
91 .execution_clk = execution_clk,
92 .space_id = space_id,
93 .num_limbs = num_limbs,
94 .dst_addr = dst_addr,
95 .value = value,
96 .radix = radix,
97 .is_output_bits = is_output_bits,
98 .limbs = {},
99 };
100
101 if (dst_out_of_range || radix_is_lt_2 || radix_is_gt_256 || invalid_bitwise_radix || invalid_num_limbs) {
103 throw ToRadixException("Error during BE conversion: Invalid parameters for ToRadix");
104 }
105
106 bool truncated = false;
107
108 if (num_limbs > 0) {
109 event.limbs.reserve(num_limbs);
110 if (is_output_bits) {
111 const auto [limbs, truncated_decomposition] = to_le_bits(value, num_limbs);
112 truncated = truncated_decomposition;
113 std::ranges::for_each(limbs.rbegin(), limbs.rend(), [&](bool bit) {
114 event.limbs.push_back(MemoryValue::from<uint1_t>(bit));
115 });
116 } else {
117 const auto [limbs, truncated_decomposition] = to_le_radix(value, num_limbs, radix);
118 truncated = truncated_decomposition;
119 std::ranges::for_each(limbs.rbegin(), limbs.rend(), [&](uint8_t limb) {
120 event.limbs.push_back(MemoryValue::from<uint8_t>(limb));
121 });
122 }
123 }
124
125 if (truncated) {
127 throw ToRadixException("Error during BE conversion: Truncation error");
128 }
129
130 // If we get to this point, we are error free.
131 for (uint32_t i = 0; i < num_limbs; i++) {
132 memory.set(dst_addr + i, event.limbs[i]);
133 }
134
136}
137
138} // namespace bb::avm2::simulation
#define AVM_HIGHEST_MEM_ADDRESS
virtual uint32_t get_execution_id() const =0
EventEmitterInterface< ToRadixMemoryEvent > & memory_events
Definition to_radix.hpp:40
EventEmitterInterface< ToRadixEvent > & events
Definition to_radix.hpp:39
std::pair< std::vector< bool >, bool > to_le_bits(const FF &value, uint32_t num_limbs) override
Definition to_radix.cpp:48
std::pair< std::vector< uint8_t >, bool > to_le_radix(const FF &value, uint32_t num_limbs, uint32_t radix) override
Definition to_radix.cpp:14
void to_be_radix(MemoryInterface &memory, const FF &value, uint32_t radix, uint32_t num_limbs, bool is_output_bits, MemoryAddress dst_addr) override
Definition to_radix.cpp:60
ExecutionIdManagerInterface & execution_id_manager
Definition to_radix.hpp:37
constexpr std::pair< uint256_t, uint256_t > divmod(const uint256_t &b) const
uint32_t dst_addr
size_t get_p_limbs_per_radix_size(size_t radix)
Definition to_radix.cpp:54
uint32_t MemoryAddress
AvmFlavorSettings::FF FF
Definition field.hpp:10
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
simulation::PublicDataTreeReadWriteEvent event