Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
uint256.hpp
Go to the documentation of this file.
1// === AUDIT STATUS ===
2// internal: { status: Planned, auditors: [], commit: }
3// external_1: { status: not started, auditors: [], commit: }
4// external_2: { status: not started, auditors: [], commit: }
5// =====================
6
18#pragma once
19
20#include "../uint128/uint128.hpp"
24#include <concepts>
25#include <cstdint>
26#include <iomanip>
27#include <iostream>
28#include <sstream>
29
30namespace bb::numeric {
31
32class alignas(32) uint256_t {
33
34 public:
35#if defined(__wasm__) || !defined(__SIZEOF_INT128__)
36#define WASM_NUM_LIMBS 9
37#define WASM_LIMB_BITS 29
38#endif
39 constexpr uint256_t() noexcept
40 : data{ 0, 0, 0, 0 }
41 {}
42
43 // Template constructor for integral types to avoid ambiguity
44 // This provides an exact match for int, unsigned int, etc., avoiding conversion ambiguity
45 // Only accepts integral types that fit in uint64_t to prevent silent truncation
46 // Note: Accepts both signed and unsigned to handle integer literals (which are signed in C++)
47 template <std::integral T>
48 requires(!std::same_as<std::remove_cv_t<T>, bool> && sizeof(T) <= sizeof(uint64_t))
49 constexpr uint256_t(T value) noexcept
50 : data{ static_cast<uint64_t>(value), 0, 0, 0 }
51 {}
52
53 constexpr uint256_t(const uint64_t a, const uint64_t b, const uint64_t c, const uint64_t d) noexcept
54 : data{ a, b, c, d }
55 {}
56
57 constexpr uint256_t(const uint128_t& a) noexcept
58 : data{ static_cast<uint64_t>(a), static_cast<uint64_t>(a >> 64), 0, 0 }
59 {}
60
61 constexpr uint256_t(const uint256_t& other) noexcept
62 : data{ other.data[0], other.data[1], other.data[2], other.data[3] }
63 {}
64 constexpr uint256_t(uint256_t&& other) noexcept = default;
65
66 explicit constexpr uint256_t(const std::string& input) noexcept
67 {
68 /* Quick and dirty conversion from a single character to its hex equivelent */
69 constexpr auto HexCharToInt = [](uint8_t Input) {
70 bool valid =
71 (Input >= 'a' && Input <= 'f') || (Input >= 'A' && Input <= 'F') || (Input >= '0' && Input <= '9');
72 if (!valid) {
73 throw_or_abort("Error, uint256 constructed from string_view with invalid hex parameter");
74 }
75 uint8_t res =
76 ((Input >= 'a') && (Input <= 'f')) ? (Input - (static_cast<uint8_t>('a') - static_cast<uint8_t>(10)))
77 : ((Input >= 'A') && (Input <= 'F')) ? (Input - (static_cast<uint8_t>('A') - static_cast<uint8_t>(10)))
78 : ((Input >= '0') && (Input <= '9')) ? (Input - static_cast<uint8_t>('0'))
79 : 0;
80 return res;
81 };
82
83 std::array<uint64_t, 4> limbs{ 0, 0, 0, 0 };
84 size_t start_index = 0;
85 if (input.size() == 66 && input[0] == '0' && input[1] == 'x') {
86 start_index = 2;
87 } else if (input.size() != 64) {
88 throw_or_abort("Error, uint256 constructed from string_view with invalid length");
89 }
90 for (size_t j = 0; j < 4; ++j) {
91
92 const size_t limb_index = start_index + j * 16;
93 for (size_t i = 0; i < 8; ++i) {
94 const size_t byte_index = limb_index + (i * 2);
95 uint8_t nibble_hi = HexCharToInt(static_cast<uint8_t>(input[byte_index]));
96 uint8_t nibble_lo = HexCharToInt(static_cast<uint8_t>(input[byte_index + 1]));
97 uint8_t byte = static_cast<uint8_t>((nibble_hi * 16) + nibble_lo);
98 limbs[j] <<= 8;
99 limbs[j] += byte;
100 }
101 }
102 data[0] = limbs[3];
103 data[1] = limbs[2];
104 data[2] = limbs[1];
105 data[3] = limbs[0];
106 }
107
108 constexpr uint256_t& operator=(const uint256_t& other) noexcept = default;
109 constexpr uint256_t& operator=(uint256_t&& other) noexcept = default;
110 constexpr ~uint256_t() noexcept = default;
111
112 explicit constexpr operator bool() const { return static_cast<bool>(data[0]); };
113
114 constexpr explicit operator uint128_t() { return (static_cast<uint128_t>(data[1]) << 64) + data[0]; }
115 template <std::integral T> explicit constexpr operator T() const { return static_cast<T>(data[0]); };
116
117 [[nodiscard]] constexpr bool get_bit(uint64_t bit_index) const;
118 [[nodiscard]] constexpr uint64_t get_msb() const;
119
120 [[nodiscard]] constexpr uint256_t slice(uint64_t start, uint64_t end) const;
121 [[nodiscard]] constexpr uint256_t pow(const uint256_t& exponent) const;
122
123 constexpr uint256_t operator+(const uint256_t& other) const;
124 constexpr uint256_t operator-(const uint256_t& other) const;
125 constexpr uint256_t operator-() const;
126
127 constexpr uint256_t operator*(const uint256_t& other) const;
128 constexpr uint256_t operator/(const uint256_t& other) const;
129 constexpr uint256_t operator%(const uint256_t& other) const;
130
131 constexpr uint256_t operator>>(const uint256_t& other) const;
132 constexpr uint256_t operator<<(const uint256_t& other) const;
133
134 constexpr uint256_t operator&(const uint256_t& other) const;
135 constexpr uint256_t operator^(const uint256_t& other) const;
136 constexpr uint256_t operator|(const uint256_t& other) const;
137 constexpr uint256_t operator~() const;
138
139 constexpr bool operator==(const uint256_t& other) const;
140 constexpr bool operator!=(const uint256_t& other) const;
141 constexpr bool operator!() const;
142
143 constexpr bool operator>(const uint256_t& other) const;
144 constexpr bool operator<(const uint256_t& other) const;
145 constexpr bool operator>=(const uint256_t& other) const;
146 constexpr bool operator<=(const uint256_t& other) const;
147
148 static constexpr size_t length() { return 256; }
149
150 constexpr uint256_t& operator+=(const uint256_t& other)
151 {
152 *this = *this + other;
153 return *this;
154 };
155 constexpr uint256_t& operator-=(const uint256_t& other)
156 {
157 *this = *this - other;
158 return *this;
159 };
160 constexpr uint256_t& operator*=(const uint256_t& other)
161 {
162 *this = *this * other;
163 return *this;
164 };
165 constexpr uint256_t& operator/=(const uint256_t& other)
166 {
167 *this = *this / other;
168 return *this;
169 };
170 constexpr uint256_t& operator%=(const uint256_t& other)
171 {
172 *this = *this % other;
173 return *this;
174 };
175
177 {
178 *this += uint256_t(1);
179 return *this;
180 };
182 {
183 *this -= uint256_t(1);
184 return *this;
185 };
186
187 constexpr uint256_t& operator&=(const uint256_t& other)
188 {
189 *this = *this & other;
190 return *this;
191 };
192 constexpr uint256_t& operator^=(const uint256_t& other)
193 {
194 *this = *this ^ other;
195 return *this;
196 };
197 constexpr uint256_t& operator|=(const uint256_t& other)
198 {
199 *this = *this | other;
200 return *this;
201 };
202
203 constexpr uint256_t& operator>>=(const uint256_t& other)
204 {
205 *this = *this >> other;
206 return *this;
207 };
208 constexpr uint256_t& operator<<=(const uint256_t& other)
209 {
210 *this = *this << other;
211 return *this;
212 };
213
214 [[nodiscard]] constexpr std::pair<uint256_t, uint256_t> mul_extended(const uint256_t& other) const;
215
216 uint64_t data[4]; // NOLINT
217
218 [[nodiscard]] constexpr std::pair<uint256_t, uint256_t> divmod(const uint256_t& b) const;
219
220 size_t hash() const noexcept { return utils::hash_as_tuple(data[0], data[1], data[2], data[3]); }
221
222 // For serialization
223 void msgpack_pack(auto& packer) const;
224 void msgpack_unpack(auto o);
225 void msgpack_schema(auto& packer) const { packer.pack_alias("uint256_t", "bin32"); }
226
227 private:
228 [[nodiscard]] static constexpr std::pair<uint64_t, uint64_t> mul_wide(uint64_t a, uint64_t b);
229 [[nodiscard]] static constexpr std::pair<uint64_t, uint64_t> addc(uint64_t a, uint64_t b, uint64_t carry_in);
230 [[nodiscard]] static constexpr uint64_t addc_discard_hi(uint64_t a, uint64_t b, uint64_t carry_in);
231 [[nodiscard]] static constexpr uint64_t sbb_discard_hi(uint64_t a, uint64_t b, uint64_t borrow_in);
232 [[nodiscard]] static constexpr std::pair<uint64_t, uint64_t> sbb(uint64_t a, uint64_t b, uint64_t borrow_in);
233 [[nodiscard]] static constexpr uint64_t mac_discard_hi(uint64_t a, uint64_t b, uint64_t c, uint64_t carry_in);
234 [[nodiscard]] static constexpr std::pair<uint64_t, uint64_t> mac(uint64_t a,
235 uint64_t b,
236 uint64_t c,
237 uint64_t carry_in);
238#if defined(__wasm__) || !defined(__SIZEOF_INT128__)
239 static constexpr void wasm_madd(const uint64_t& left_limb,
240 const uint64_t* right_limbs,
241 uint64_t& result_0,
242 uint64_t& result_1,
243 uint64_t& result_2,
244 uint64_t& result_3,
245 uint64_t& result_4,
246 uint64_t& result_5,
247 uint64_t& result_6,
248 uint64_t& result_7,
249 uint64_t& result_8);
250 [[nodiscard]] static constexpr std::array<uint64_t, WASM_NUM_LIMBS> wasm_convert(const uint64_t* data);
251#endif
252};
253
254inline std::ostream& operator<<(std::ostream& os, uint256_t const& a)
255{
256 std::ios_base::fmtflags f(os.flags());
257 os << std::hex << "0x" << std::setfill('0') << std::setw(16) << a.data[3] << std::setw(16) << a.data[2]
258 << std::setw(16) << a.data[1] << std::setw(16) << a.data[0];
259 os.flags(f);
260 return os;
261}
262
263template <typename B> inline void read(B& it, uint256_t& value)
264{
265 using serialize::read;
266 uint64_t a = 0;
267 uint64_t b = 0;
268 uint64_t c = 0;
269 uint64_t d = 0;
270 read(it, d);
271 read(it, c);
272 read(it, b);
273 read(it, a);
274 value = uint256_t(a, b, c, d);
275}
276
277template <typename B> inline void write(B& it, uint256_t const& value)
278{
279 using serialize::write;
280 write(it, value.data[3]);
281 write(it, value.data[2]);
282 write(it, value.data[1]);
283 write(it, value.data[0]);
284}
285
286} // namespace bb::numeric
287
288#include "./uint256_impl.hpp"
289
290// disable linter errors; we want to expose a global uint256_t type to mimic uint64_t, uint32_t etc
291// NOLINTNEXTLINE(tidymisc-unused-using-decls, google-global-names-in-headers, misc-unused-using-decls)
constexpr std::pair< uint256_t, uint256_t > mul_extended(const uint256_t &other) const
Compute the result of multiplication modulu 2**512.
constexpr uint256_t operator^(const uint256_t &other) const
constexpr uint256_t operator~() const
constexpr uint256_t & operator>>=(const uint256_t &other)
Definition uint256.hpp:203
constexpr uint256_t operator%(const uint256_t &other) const
constexpr uint256_t(uint256_t &&other) noexcept=default
static constexpr std::pair< uint64_t, uint64_t > addc(uint64_t a, uint64_t b, uint64_t carry_in)
constexpr uint256_t operator*(const uint256_t &other) const
constexpr uint256_t & operator<<=(const uint256_t &other)
Definition uint256.hpp:208
constexpr uint256_t & operator++()
Definition uint256.hpp:176
constexpr uint256_t operator+(const uint256_t &other) const
constexpr uint256_t & operator*=(const uint256_t &other)
Definition uint256.hpp:160
static constexpr uint64_t sbb_discard_hi(uint64_t a, uint64_t b, uint64_t borrow_in)
void msgpack_schema(auto &packer) const
Definition uint256.hpp:225
static constexpr std::array< uint64_t, WASM_NUM_LIMBS > wasm_convert(const uint64_t *data)
Convert from 4 64-bit limbs to 9 29-bit limbs.
size_t hash() const noexcept
Definition uint256.hpp:220
constexpr bool get_bit(uint64_t bit_index) const
constexpr uint256_t() noexcept
Definition uint256.hpp:39
constexpr uint256_t & operator&=(const uint256_t &other)
Definition uint256.hpp:187
constexpr uint256_t & operator%=(const uint256_t &other)
Definition uint256.hpp:170
constexpr uint256_t operator<<(const uint256_t &other) const
constexpr uint256_t(const std::string &input) noexcept
Definition uint256.hpp:66
constexpr bool operator!() const
constexpr uint256_t & operator-=(const uint256_t &other)
Definition uint256.hpp:155
constexpr bool operator==(const uint256_t &other) const
constexpr uint256_t operator&(const uint256_t &other) const
constexpr uint256_t & operator=(const uint256_t &other) noexcept=default
static constexpr void wasm_madd(const uint64_t &left_limb, const uint64_t *right_limbs, uint64_t &result_0, uint64_t &result_1, uint64_t &result_2, uint64_t &result_3, uint64_t &result_4, uint64_t &result_5, uint64_t &result_6, uint64_t &result_7, uint64_t &result_8)
Multiply one limb by 9 limbs and add to resulting limbs.
constexpr bool operator>(const uint256_t &other) const
static constexpr std::pair< uint64_t, uint64_t > mac(uint64_t a, uint64_t b, uint64_t c, uint64_t carry_in)
constexpr bool operator<(const uint256_t &other) const
constexpr uint256_t & operator^=(const uint256_t &other)
Definition uint256.hpp:192
static constexpr std::pair< uint64_t, uint64_t > sbb(uint64_t a, uint64_t b, uint64_t borrow_in)
constexpr bool operator>=(const uint256_t &other) const
constexpr uint256_t operator|(const uint256_t &other) const
constexpr bool operator!=(const uint256_t &other) const
constexpr uint256_t operator-() const
constexpr uint256_t & operator|=(const uint256_t &other)
Definition uint256.hpp:197
static constexpr uint64_t mac_discard_hi(uint64_t a, uint64_t b, uint64_t c, uint64_t carry_in)
constexpr uint256_t operator/(const uint256_t &other) const
constexpr uint256_t pow(const uint256_t &exponent) const
constexpr uint256_t slice(uint64_t start, uint64_t end) const
static constexpr std::pair< uint64_t, uint64_t > mul_wide(uint64_t a, uint64_t b)
static constexpr uint64_t addc_discard_hi(uint64_t a, uint64_t b, uint64_t carry_in)
constexpr bool operator<=(const uint256_t &other) const
constexpr ~uint256_t() noexcept=default
constexpr std::pair< uint256_t, uint256_t > divmod(const uint256_t &b) const
constexpr uint256_t & operator/=(const uint256_t &other)
Definition uint256.hpp:165
constexpr uint256_t operator>>(const uint256_t &other) const
constexpr uint256_t & operator=(uint256_t &&other) noexcept=default
constexpr uint256_t(const uint128_t &a) noexcept
Definition uint256.hpp:57
constexpr uint256_t(const uint256_t &other) noexcept
Definition uint256.hpp:61
constexpr uint64_t get_msb() const
constexpr uint256_t & operator--()
Definition uint256.hpp:181
constexpr uint256_t(T value) noexcept
Definition uint256.hpp:49
constexpr uint256_t(const uint64_t a, const uint64_t b, const uint64_t c, const uint64_t d) noexcept
Definition uint256.hpp:53
void msgpack_pack(auto &packer) const
constexpr uint256_t & operator+=(const uint256_t &other)
Definition uint256.hpp:150
static constexpr size_t length()
Definition uint256.hpp:148
FF a
FF b
void read(B &it, uint256_t &value)
Definition uint256.hpp:263
std::ostream & operator<<(std::ostream &os, uint256_t const &a)
Definition uint256.hpp:254
void write(B &it, uint256_t const &value)
Definition uint256.hpp:277
size_t hash_as_tuple(const Ts &... ts)
Definition utils.hpp:22
void read(auto &it, msgpack_concepts::HasMsgPack auto &obj)
Automatically derived read for any object that defines .msgpack() (implicitly defined by MSGPACK_FIEL...
void write(auto &buf, const msgpack_concepts::HasMsgPack auto &obj)
Automatically derived write for any object that defines .msgpack() (implicitly defined by MSGPACK_FIE...
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
unsigned __int128 uint128_t
Definition serialize.hpp:44
void throw_or_abort(std::string const &err)