Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
uintx.test.cpp
Go to the documentation of this file.
1#include "./uintx.hpp"
2#include "../random/engine.hpp"
3#include "./uintx_impl.hpp"
5#include <gtest/gtest.h>
6
7using namespace bb;
8
9// Explicit instantiation of barrett_reduction for the test-only 1024-bit modulus.
10namespace bb::numeric {
11constexpr uint512_t TEST_MODULUS(uint256_t{ "0x04689e957a1242c84a50189c6d96cadca602072d09eac1013b5458a2275d69b1" },
12 uint256_t{ "0x0925c4b8763cbf9c599a6f7c0348d21cb00b85511637560626edfa5c34c6b38d" });
14} // namespace bb::numeric
15
16namespace {
18} // namespace
19
20TEST(uintx, BarrettReduction512)
21{
23
24 static constexpr uint64_t modulus_0 = 0x3C208C16D87CFD47UL;
25 static constexpr uint64_t modulus_1 = 0x97816a916871ca8dUL;
26 static constexpr uint64_t modulus_2 = 0xb85045b68181585dUL;
27 static constexpr uint64_t modulus_3 = 0x30644e72e131a029UL;
28 constexpr uint256_t modulus(modulus_0, modulus_1, modulus_2, modulus_3);
29
30 const auto [quotient_result, remainder_result] = x.barrett_reduction<modulus>();
31 const auto [quotient_expected, remainder_expected] = x.divmod_base(uint512_t(modulus));
32 EXPECT_EQ(quotient_result, quotient_expected);
33 EXPECT_EQ(remainder_result, remainder_expected);
34}
35
36TEST(uintx, BarrettReduction1024)
37{
39
40 constexpr uint256_t modulus_lo{ "0x04689e957a1242c84a50189c6d96cadca602072d09eac1013b5458a2275d69b1" };
41 constexpr uint256_t modulus_hi{ "0x0925c4b8763cbf9c599a6f7c0348d21cb00b85511637560626edfa5c34c6b38d" };
42 constexpr uint512_t modulus{ modulus_lo, modulus_hi };
43
44 const auto [quotient_result, remainder_result] = x.barrett_reduction<modulus>();
45 const auto [quotient_expected, remainder_expected] = x.divmod_base(uint1024_t(modulus));
46 EXPECT_EQ(quotient_result, quotient_expected);
47 EXPECT_EQ(remainder_result, remainder_expected);
48}
49
50TEST(uintx, GetBit)
51{
52 constexpr uint256_t lo{ 0b0110011001110010011001100111001001100110011100100110011001110011,
53 0b1001011101101010101010100100101101101001001010010101110101010111,
54 0b0101010010010101111100001011011010101010110101110110110111010101,
55 0b0101011010101010100010001000101011010101010101010010000100000000 };
56
57 constexpr uint256_t hi{ 0b0110011001110010011001100111001001100110011100100110011001110011,
58 0b1001011101101010101010100100101101101001001010010101110101010111,
59 0b0101010010010101111100001011011010101010110101110110110111010101,
60 0b0101011010101010100010001000101011010101010101010010000100000000 };
61
62 constexpr uint1024_t a(uint512_t(lo, hi), uint512_t(lo, hi));
63 uint1024_t res(0);
64 for (size_t i = 0; i < 1024; ++i) {
65 res += a.get_bit(i) ? (uint1024_t(1) << i) : 0;
66 }
67
68 EXPECT_EQ(a, res);
69}
70
72{
75
76 uint1024_t c = (a + b) * (a + b);
77 uint1024_t d = (a * a) + (b * b) + (a * b) + (a * b);
78 EXPECT_EQ(c, d);
79}
80
81TEST(uintx, DivAndMod)
82{
83 for (size_t i = 0; i < 256; ++i) {
86
87 uint1024_t q = a / b;
88 uint1024_t r = a % b;
89
90 uint1024_t c = q * b + r;
91 EXPECT_EQ(c, a);
92 }
93
95 uint1024_t a = 0;
96 // Since we have an ASSERT in div_mod now we have to use EXPECT_DEATH
97 // but we don't want to use it, so we skip the division by zero check
98
99 // b = a;
100 auto q = a / b;
101 auto r = a % b;
102
103 EXPECT_EQ(q, uint1024_t(0));
104 EXPECT_EQ(r, uint1024_t(0));
105}
106
107// We should not be depending on ecc in numeric.
108TEST(uintx, DISABLEDMulmod)
109{
110 /*
111 fq a = fq::random_element();
112 fq b = fq::random_element();
113 // fq a_converted = a.from_montgomery_form();
114 // fq b_converted = b.from_montgomery_form();
115 uint256_t a_uint =
116 uint256_t(a); // { a_converted.data[0], a_converted.data[1], a_converted.data[2], a_converted.data[3] };
117 uint256_t b_uint =
118 uint256_t(b); // { b_converted.data[0], b_converted.data[1], b_converted.data[2], b_converted.data[3] };
119 uint256_t modulus_uint{ bb::Bn254FqParams::modulus_0,
120 Bn254FqParams::modulus_1,
121 Bn254FqParams::modulus_2,
122 Bn254FqParams::modulus_3 };
123 uint1024_t a_uintx = uint1024_t(uint512_t(a_uint));
124 uint1024_t b_uintx = uint1024_t(uint512_t(b_uint));
125 uint1024_t modulus_uintx = uint1024_t(uint512_t(modulus_uint));
126
127 const auto [quotient, remainder] = (a_uintx * b_uintx).divmod(modulus_uintx);
128
129 // fq expected_a = a_converted.to_montgomery_form();
130 // fq expected_b = b_converted.to_montgomery_form();
131 fq expected = (a * b).from_montgomery_form();
132
133 EXPECT_EQ(remainder.lo.lo.data[0], expected.data[0]);
134 EXPECT_EQ(remainder.lo.lo.data[1], expected.data[1]);
135 EXPECT_EQ(remainder.lo.lo.data[2], expected.data[2]);
136 EXPECT_EQ(remainder.lo.lo.data[3], expected.data[3]);
137
138 const auto rhs = (quotient * modulus_uintx) + remainder;
139 const auto lhs = a_uintx * b_uintx;
140 EXPECT_EQ(lhs, rhs);
141 */
142}
143
145{
148
149 uint1024_t c = (a - b) * (a + b);
150 uint1024_t d = (a * a) - (b * b);
151
152 EXPECT_EQ(c, d);
153
154 uint1024_t e = 0;
155 e = e - 1;
156
157 EXPECT_EQ(e.lo.lo.data[0], UINT64_MAX);
158 EXPECT_EQ(e.lo.lo.data[1], UINT64_MAX);
159 EXPECT_EQ(e.lo.lo.data[2], UINT64_MAX);
160 EXPECT_EQ(e.lo.lo.data[3], UINT64_MAX);
161 EXPECT_EQ(e.lo.hi.data[0], UINT64_MAX);
162 EXPECT_EQ(e.lo.hi.data[1], UINT64_MAX);
163 EXPECT_EQ(e.lo.hi.data[2], UINT64_MAX);
164 EXPECT_EQ(e.lo.hi.data[3], UINT64_MAX);
165 EXPECT_EQ(e.hi.lo.data[0], UINT64_MAX);
166 EXPECT_EQ(e.hi.lo.data[1], UINT64_MAX);
167 EXPECT_EQ(e.hi.lo.data[2], UINT64_MAX);
168 EXPECT_EQ(e.hi.lo.data[3], UINT64_MAX);
169 EXPECT_EQ(e.hi.hi.data[0], UINT64_MAX);
170 EXPECT_EQ(e.hi.hi.data[1], UINT64_MAX);
171 EXPECT_EQ(e.hi.hi.data[2], UINT64_MAX);
172 EXPECT_EQ(e.hi.hi.data[3], UINT64_MAX);
173}
174
176{
179
180 uint1024_t c = a & b;
181
182 EXPECT_EQ(c.lo, a.lo & b.lo);
183 EXPECT_EQ(c.hi, a.hi & b.hi);
184}
185
187{
190
191 uint1024_t c = a | b;
192
193 EXPECT_EQ(c.lo, a.lo | b.lo);
194 EXPECT_EQ(c.hi, a.hi | b.hi);
195}
196
198{
201
202 uint1024_t c = a ^ b;
203
204 EXPECT_EQ(c.lo, a.lo ^ b.lo);
205 EXPECT_EQ(c.hi, a.hi ^ b.hi);
206}
207
208TEST(uintx, BitNot)
209{
211
212 uint1024_t c = ~a;
213
214 EXPECT_EQ(c.lo, ~a.lo);
215 EXPECT_EQ(c.hi, ~a.hi);
216}
217
218TEST(uintx, LogicNot)
219{
220 uint1024_t a(1);
221
222 bool b = !a;
223
224 EXPECT_EQ(b, false);
225
226 uint1024_t c(0);
227
228 EXPECT_EQ(!c, true);
229}
230
231TEST(uintx, NotEqual)
232{
233 uint1024_t a(1);
234 uint1024_t b(1);
235 EXPECT_EQ(a != b, false);
236
237 a = uint1024_t(0);
238 EXPECT_EQ(a != b, true);
239}
240
241// We should not be depending on ecc in numeric.
242TEST(uintx, DISABLEDInvmod)
243{
244 /*
245 uint256_t prime_lo = prime_256;
246 uint1024_t prime = uint1024_t(uint512_t(prime_lo));
247 uint256_t target_lo = engine.get_random_uint256();
248 uint1024_t target = uint1024_t(uint512_t(target_lo));
249 uint256_t inverse = uint256_t(uint512_t(target.invmod(prime)));
250
251 uint256_t expected = uint256_t(fr(target_lo).invert());
252 EXPECT_EQ(inverse, expected);
253 */
254}
255
256TEST(uintx, InvmodRegressionCheck)
257{
258 const std::array<uint8_t, 64> _a = { 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x0D, 0x6A, 0x2B, 0x19, 0x52,
259 0x2D, 0xF7, 0xAF, 0xC7, 0x95, 0x68, 0x22, 0xD7, 0xF2, 0x21, 0xA3, 0x00, 0x00,
260 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
261 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
262 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
263
264 const std::array<uint8_t, 64> _b = { 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x5D, 0x32, 0xDA, 0x10,
265 0x4F, 0x1D, 0xD6, 0xCA, 0x50, 0x56, 0x11, 0x18, 0x18, 0xC2, 0xD4, 0x6C, 0x70,
266 0x60, 0xD9, 0xB8, 0xFA, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
267 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE2, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
268 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xFF, 0xFF };
269
270 const std::array<uint8_t, 64> expected_result = {
271 0x9F, 0x2F, 0xAA, 0x7B, 0xD7, 0x5A, 0x99, 0x56, 0x04, 0x68, 0x6C, 0x9D, 0xD8, 0x47, 0x6B, 0x52,
272 0xF0, 0x10, 0xD2, 0xA8, 0x62, 0x96, 0x60, 0x68, 0xBE, 0x18, 0x21, 0xA1, 0xCA, 0x6F, 0x41, 0x9C,
273 0x37, 0x42, 0x2F, 0xA3, 0x1B, 0x41, 0x7B, 0xAA, 0xEE, 0x6D, 0x9E, 0x03, 0x78, 0x71, 0xEF, 0xCF,
274 0x90, 0x85, 0xEF, 0x17, 0x59, 0xC4, 0xEE, 0x24, 0x80, 0xDE, 0x7A, 0x58, 0xA5, 0x42, 0x8F, 0x97,
275 };
276
277 std::array<uint8_t, 64> _res;
278
279 uint512_t a;
280 uint512_t b;
281
282 memcpy(a.lo.data, &_a[0], 32);
283 memcpy(a.hi.data, &_a[0] + 32, 32);
284
285 memcpy(b.lo.data, &_b[0], 32);
286 memcpy(b.hi.data, &_b[0] + 32, 32);
287 const auto res = a.invmod(b);
288 memcpy(&_res[0], res.lo.data, 32);
289 memcpy(&_res[0] + 32, res.hi.data, 32);
290
291 EXPECT_EQ(memcmp(&_res[0], &expected_result[0], sizeof(expected_result)), 0);
292}
293TEST(uintx, DISABLEDRInv)
294{
295 /*
296 uint512_t r{ 0, 1 };
297 // -(1/q) mod r
298 uint512_t q{ -prime_256, 0 };
299 uint256_t q_inv = q.invmod(r).lo;
300 uint64_t result = q_inv.data[0];
301 EXPECT_EQ(result, Bn254FrParams::r_inv);
302 */
303}
304
305TEST(uintx, Slice)
306{
307 // Construct a uint512_t with known lo and hi halves
308 uint256_t lo_val(1, 2, 3, 4);
309 uint256_t hi_val(5, 6, 7, 8);
310 uint512_t val(lo_val, hi_val);
311
312 // Slice the lower 256 bits
313 uint512_t lower = val.slice(0, 256);
314 EXPECT_EQ(lower.lo, lo_val);
315 EXPECT_EQ(lower.hi, uint256_t(0));
316
317 // Slice the upper 256 bits
318 uint512_t upper = val.slice(256, 512);
319 EXPECT_EQ(upper.lo, hi_val);
320 EXPECT_EQ(upper.hi, uint256_t(0));
321
322 // Slice a sub-limb range within lo
323 uint512_t small_slice = val.slice(0, 64);
324 EXPECT_EQ(static_cast<uint64_t>(small_slice), uint64_t(1));
325
326 // Slice crossing the lo/hi boundary
327 uint512_t cross_boundary = val.slice(128, 384);
328 // Should get bits [128..256) from lo (limbs 2,3) and bits [256..384) from hi (limbs 0,1)
329 uint512_t expected_cross(uint256_t(3, 4, 5, 6));
330 EXPECT_EQ(cross_boundary, expected_cross);
331
332 // Full-width slice should return the original value
333 EXPECT_EQ(val.slice(0, 512), val);
334}
335
336TEST(uintx, BarrettReductionRegression)
337{
338 // Test specific modulus and self values that may cause issues
339 constexpr uint256_t modulus{ "0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff" };
340
341 // Test case 1: self = 0xffffffff0000000000000000000000000000000000000000003a000000000000
342 // This is a 256-bit value, so we need to construct it as a single uint256_t
343 constexpr uint256_t self_value{ "0xffffffff0000000000000000000000000000000000000000003a000000000000" };
344 uint512_t self(self_value);
345 self = self << 256;
346 const auto [quotient_result, remainder_result] = self.barrett_reduction<modulus>();
347 const auto [quotient_expected, remainder_expected] = self.divmod_base(uint512_t(modulus));
348 EXPECT_EQ(quotient_result, quotient_expected);
349 EXPECT_EQ(remainder_result, remainder_expected);
350}
uint512_t get_random_uint512()
Definition engine.hpp:38
uint1024_t get_random_uint1024()
Definition engine.hpp:46
constexpr uintx slice(const uint64_t start, const uint64_t end) const
Definition uintx.hpp:81
std::pair< uintx, uintx > divmod_base(const uintx &b) const
std::pair< uintx, uintx > barrett_reduction() const
FF a
FF b
bool expected_result
numeric::RNG & engine
constexpr uint512_t TEST_MODULUS(uint256_t{ "0x04689e957a1242c84a50189c6d96cadca602072d09eac1013b5458a2275d69b1" }, uint256_t{ "0x0925c4b8763cbf9c599a6f7c0348d21cb00b85511637560626edfa5c34c6b38d" })
uintx< uint256_t > uint512_t
Definition uintx.hpp:306
RNG & get_debug_randomness(bool reset, std::uint_fast64_t seed)
Definition engine.cpp:217
uintx< uint512_t > uint1024_t
Definition uintx.hpp:308
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
TEST(BoomerangMegaCircuitBuilder, BasicCircuit)
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13