barretenberg
Loading...
Searching...
No Matches
uint128.hpp
1#pragma once
2#include <cstdint>
3#include <iomanip>
4#include <ostream>
5
6#ifdef __i386__
7#include "barretenberg/common/serialize.hpp"
8#include <concepts>
9
10namespace numeric {
11
12class alignas(32) uint128_t {
13 public:
14 uint32_t data[4]; // NOLINT
15
16 constexpr uint128_t(const uint64_t a = 0)
17 : data{ static_cast<uint32_t>(a), static_cast<uint32_t>(a >> 32), 0, 0 }
18 {}
19
20 constexpr uint128_t(const uint32_t a, const uint32_t b, const uint32_t c, const uint32_t d)
21 : data{ a, b, c, d }
22 {}
23
24 constexpr uint128_t(const uint128_t& other)
25 : data{ other.data[0], other.data[1], other.data[2], other.data[3] }
26 {}
27 constexpr uint128_t(uint128_t&& other) = default;
28
29 static constexpr uint128_t from_uint64(const uint64_t a)
30 {
31 return { static_cast<uint32_t>(a), static_cast<uint32_t>(a >> 32), 0, 0 };
32 }
33
34 constexpr explicit operator uint64_t() { return (static_cast<uint64_t>(data[1]) << 32) + data[0]; }
35
36 constexpr uint128_t& operator=(const uint128_t& other) = default;
37 constexpr uint128_t& operator=(uint128_t&& other) = default;
38 constexpr ~uint128_t() = default;
39 explicit constexpr operator bool() const { return static_cast<bool>(data[0]); };
40
41 template <std::integral T> explicit constexpr operator T() const { return static_cast<T>(data[0]); };
42
43 [[nodiscard]] constexpr bool get_bit(uint64_t bit_index) const;
44 [[nodiscard]] constexpr uint64_t get_msb() const;
45
46 [[nodiscard]] constexpr uint128_t slice(uint64_t start, uint64_t end) const;
47 [[nodiscard]] constexpr uint128_t pow(const uint128_t& exponent) const;
48
49 constexpr uint128_t operator+(const uint128_t& other) const;
50 constexpr uint128_t operator-(const uint128_t& other) const;
51 constexpr uint128_t operator-() const;
52
53 constexpr uint128_t operator*(const uint128_t& other) const;
54 constexpr uint128_t operator/(const uint128_t& other) const;
55 constexpr uint128_t operator%(const uint128_t& other) const;
56
57 constexpr uint128_t operator>>(const uint128_t& other) const;
58 constexpr uint128_t operator<<(const uint128_t& other) const;
59
60 constexpr uint128_t operator&(const uint128_t& other) const;
61 constexpr uint128_t operator^(const uint128_t& other) const;
62 constexpr uint128_t operator|(const uint128_t& other) const;
63 constexpr uint128_t operator~() const;
64
65 constexpr bool operator==(const uint128_t& other) const;
66 constexpr bool operator!=(const uint128_t& other) const;
67 constexpr bool operator!() const;
68
69 constexpr bool operator>(const uint128_t& other) const;
70 constexpr bool operator<(const uint128_t& other) const;
71 constexpr bool operator>=(const uint128_t& other) const;
72 constexpr bool operator<=(const uint128_t& other) const;
73
74 static constexpr size_t length() { return 128; }
75
76 constexpr uint128_t& operator+=(const uint128_t& other)
77 {
78 *this = *this + other;
79 return *this;
80 };
81 constexpr uint128_t& operator-=(const uint128_t& other)
82 {
83 *this = *this - other;
84 return *this;
85 };
86 constexpr uint128_t& operator*=(const uint128_t& other)
87 {
88 *this = *this * other;
89 return *this;
90 };
91 constexpr uint128_t& operator/=(const uint128_t& other)
92 {
93 *this = *this / other;
94 return *this;
95 };
96 constexpr uint128_t& operator%=(const uint128_t& other)
97 {
98 *this = *this % other;
99 return *this;
100 };
101
102 constexpr uint128_t& operator++()
103 {
104 *this += uint128_t(1);
105 return *this;
106 };
107 constexpr uint128_t& operator--()
108 {
109 *this -= uint128_t(1);
110 return *this;
111 };
112
113 constexpr uint128_t& operator&=(const uint128_t& other)
114 {
115 *this = *this & other;
116 return *this;
117 };
118 constexpr uint128_t& operator^=(const uint128_t& other)
119 {
120 *this = *this ^ other;
121 return *this;
122 };
123 constexpr uint128_t& operator|=(const uint128_t& other)
124 {
125 *this = *this | other;
126 return *this;
127 };
128
129 constexpr uint128_t& operator>>=(const uint128_t& other)
130 {
131 *this = *this >> other;
132 return *this;
133 };
134 constexpr uint128_t& operator<<=(const uint128_t& other)
135 {
136 *this = *this << other;
137 return *this;
138 };
139
140 [[nodiscard]] constexpr std::pair<uint128_t, uint128_t> mul_extended(const uint128_t& other) const;
141
142 [[nodiscard]] constexpr std::pair<uint128_t, uint128_t> divmod(const uint128_t& b) const;
143
144 private:
145 [[nodiscard]] static constexpr std::pair<uint32_t, uint32_t> mul_wide(uint32_t a, uint32_t b);
146 [[nodiscard]] static constexpr std::pair<uint32_t, uint32_t> addc(uint32_t a, uint32_t b, uint32_t carry_in);
147 [[nodiscard]] static constexpr uint32_t addc_discard_hi(uint32_t a, uint32_t b, uint32_t carry_in);
148 [[nodiscard]] static constexpr uint32_t sbb_discard_hi(uint32_t a, uint32_t b, uint32_t borrow_in);
149
150 [[nodiscard]] static constexpr std::pair<uint32_t, uint32_t> sbb(uint32_t a, uint32_t b, uint32_t borrow_in);
151 [[nodiscard]] static constexpr uint32_t mac_discard_hi(uint32_t a, uint32_t b, uint32_t c, uint32_t carry_in);
152 [[nodiscard]] static constexpr std::pair<uint32_t, uint32_t> mac(uint32_t a,
153 uint32_t b,
154 uint32_t c,
155 uint32_t carry_in);
156};
157
158inline std::ostream& operator<<(std::ostream& os, uint128_t const& a)
159{
160 std::ios_base::fmtflags f(os.flags());
161 os << std::hex << "0x" << std::setfill('0') << std::setw(8) << a.data[3] << std::setw(8) << a.data[2]
162 << std::setw(8) << a.data[1] << std::setw(8) << a.data[0];
163 os.flags(f);
164 return os;
165}
166
167template <typename B> inline void read(B& it, uint128_t& value)
168{
169 using serialize::read;
170 uint32_t a = 0;
171 uint32_t b = 0;
172 uint32_t c = 0;
173 uint32_t d = 0;
174 read(it, d);
175 read(it, c);
176 read(it, b);
177 read(it, a);
178 value = uint128_t(a, b, c, d);
179}
180
181template <typename B> inline void write(B& it, uint128_t const& value)
182{
183 using serialize::write;
184 write(it, value.data[3]);
185 write(it, value.data[2]);
186 write(it, value.data[1]);
187 write(it, value.data[0]);
188}
189
190} // namespace numeric
191
192#include "./uint128_impl.hpp"
193
194// disable linter errors; we want to expose a global uint128_t type to mimic uint64_t, uint32_t etc
195// NOLINTNEXTLINE(tidymisc-unused-using-decls, google-global-names-in-headers, misc-unused-using-decls)
196using numeric::uint128_t;
197#else
198__extension__ using uint128_t = unsigned __int128;
199
200namespace std {
201// can ignore linter error for streaming operations, we need to add to std namespace to support printing this type!
202// NOLINTNEXTLINE(cert-dcl58-cpp)
203inline std::ostream& operator<<(std::ostream& os, uint128_t const& a)
204{
205 std::ios_base::fmtflags f(os.flags());
206 os << std::hex << "0x" << std::setfill('0') << std::setw(16) << static_cast<uint64_t>(a >> 64) << std::setw(16)
207 << static_cast<uint64_t>(a);
208 os.flags(f);
209 return os;
210}
211} // namespace std
212#endif
Definition: field2_declarations.hpp:6