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"
4#include <gtest/gtest.h>
5
6using namespace bb;
7
8namespace {
10} // namespace
11
12TEST(uintx, BarrettReduction512)
13{
15
16 static constexpr uint64_t modulus_0 = 0x3C208C16D87CFD47UL;
17 static constexpr uint64_t modulus_1 = 0x97816a916871ca8dUL;
18 static constexpr uint64_t modulus_2 = 0xb85045b68181585dUL;
19 static constexpr uint64_t modulus_3 = 0x30644e72e131a029UL;
20 constexpr uint256_t modulus(modulus_0, modulus_1, modulus_2, modulus_3);
21
22 const auto [quotient_result, remainder_result] = x.barrett_reduction<modulus>();
23 const auto [quotient_expected, remainder_expected] = x.divmod_base(uint512_t(modulus));
24 EXPECT_EQ(quotient_result, quotient_expected);
25 EXPECT_EQ(remainder_result, remainder_expected);
26}
27
28TEST(uintx, BarrettReduction1024)
29{
31
32 constexpr uint256_t modulus_lo{ "0x04689e957a1242c84a50189c6d96cadca602072d09eac1013b5458a2275d69b1" };
33 constexpr uint256_t modulus_hi{ "0x0925c4b8763cbf9c599a6f7c0348d21cb00b85511637560626edfa5c34c6b38d" };
34 constexpr uint512_t modulus{ modulus_lo, modulus_hi };
35
36 const auto [quotient_result, remainder_result] = x.barrett_reduction<modulus>();
37 const auto [quotient_expected, remainder_expected] = x.divmod_base(uint1024_t(modulus));
38 EXPECT_EQ(quotient_result, quotient_expected);
39 EXPECT_EQ(remainder_result, remainder_expected);
40}
41
42TEST(uintx, GetBit)
43{
44 constexpr uint256_t lo{ 0b0110011001110010011001100111001001100110011100100110011001110011,
45 0b1001011101101010101010100100101101101001001010010101110101010111,
46 0b0101010010010101111100001011011010101010110101110110110111010101,
47 0b0101011010101010100010001000101011010101010101010010000100000000 };
48
49 constexpr uint256_t hi{ 0b0110011001110010011001100111001001100110011100100110011001110011,
50 0b1001011101101010101010100100101101101001001010010101110101010111,
51 0b0101010010010101111100001011011010101010110101110110110111010101,
52 0b0101011010101010100010001000101011010101010101010010000100000000 };
53
54 constexpr uint1024_t a(uint512_t(lo, hi), uint512_t(lo, hi));
55 uint1024_t res(0);
56 for (size_t i = 0; i < 1024; ++i) {
57 res += a.get_bit(i) ? (uint1024_t(1) << i) : 0;
58 }
59
60 EXPECT_EQ(a, res);
61}
62
64{
67
68 uint1024_t c = (a + b) * (a + b);
69 uint1024_t d = (a * a) + (b * b) + (a * b) + (a * b);
70 EXPECT_EQ(c, d);
71}
72
73TEST(uintx, DivAndMod)
74{
75 for (size_t i = 0; i < 256; ++i) {
78
79 uint1024_t q = a / b;
80 uint1024_t r = a % b;
81
82 uint1024_t c = q * b + r;
83 EXPECT_EQ(c, a);
84 }
85
87 uint1024_t a = 0;
88 // Since we have an ASSERT in div_mod now we have to use EXPECT_DEATH
89 // but we don't want to use it, so we skip the division by zero check
90
91 // b = a;
92 auto q = a / b;
93 auto r = a % b;
94
95 EXPECT_EQ(q, uint1024_t(0));
96 EXPECT_EQ(r, uint1024_t(0));
97}
98
99// We should not be depending on ecc in numeric.
100TEST(uintx, DISABLEDMulmod)
101{
102 /*
103 fq a = fq::random_element();
104 fq b = fq::random_element();
105 // fq a_converted = a.from_montgomery_form();
106 // fq b_converted = b.from_montgomery_form();
107 uint256_t a_uint =
108 uint256_t(a); // { a_converted.data[0], a_converted.data[1], a_converted.data[2], a_converted.data[3] };
109 uint256_t b_uint =
110 uint256_t(b); // { b_converted.data[0], b_converted.data[1], b_converted.data[2], b_converted.data[3] };
111 uint256_t modulus_uint{ bb::Bn254FqParams::modulus_0,
112 Bn254FqParams::modulus_1,
113 Bn254FqParams::modulus_2,
114 Bn254FqParams::modulus_3 };
115 uint1024_t a_uintx = uint1024_t(uint512_t(a_uint));
116 uint1024_t b_uintx = uint1024_t(uint512_t(b_uint));
117 uint1024_t modulus_uintx = uint1024_t(uint512_t(modulus_uint));
118
119 const auto [quotient, remainder] = (a_uintx * b_uintx).divmod(modulus_uintx);
120
121 // fq expected_a = a_converted.to_montgomery_form();
122 // fq expected_b = b_converted.to_montgomery_form();
123 fq expected = (a * b).from_montgomery_form();
124
125 EXPECT_EQ(remainder.lo.lo.data[0], expected.data[0]);
126 EXPECT_EQ(remainder.lo.lo.data[1], expected.data[1]);
127 EXPECT_EQ(remainder.lo.lo.data[2], expected.data[2]);
128 EXPECT_EQ(remainder.lo.lo.data[3], expected.data[3]);
129
130 const auto rhs = (quotient * modulus_uintx) + remainder;
131 const auto lhs = a_uintx * b_uintx;
132 EXPECT_EQ(lhs, rhs);
133 */
134}
135
137{
140
141 uint1024_t c = (a - b) * (a + b);
142 uint1024_t d = (a * a) - (b * b);
143
144 EXPECT_EQ(c, d);
145
146 uint1024_t e = 0;
147 e = e - 1;
148
149 EXPECT_EQ(e.lo.lo.data[0], UINT64_MAX);
150 EXPECT_EQ(e.lo.lo.data[1], UINT64_MAX);
151 EXPECT_EQ(e.lo.lo.data[2], UINT64_MAX);
152 EXPECT_EQ(e.lo.lo.data[3], UINT64_MAX);
153 EXPECT_EQ(e.lo.hi.data[0], UINT64_MAX);
154 EXPECT_EQ(e.lo.hi.data[1], UINT64_MAX);
155 EXPECT_EQ(e.lo.hi.data[2], UINT64_MAX);
156 EXPECT_EQ(e.lo.hi.data[3], UINT64_MAX);
157 EXPECT_EQ(e.hi.lo.data[0], UINT64_MAX);
158 EXPECT_EQ(e.hi.lo.data[1], UINT64_MAX);
159 EXPECT_EQ(e.hi.lo.data[2], UINT64_MAX);
160 EXPECT_EQ(e.hi.lo.data[3], UINT64_MAX);
161 EXPECT_EQ(e.hi.hi.data[0], UINT64_MAX);
162 EXPECT_EQ(e.hi.hi.data[1], UINT64_MAX);
163 EXPECT_EQ(e.hi.hi.data[2], UINT64_MAX);
164 EXPECT_EQ(e.hi.hi.data[3], UINT64_MAX);
165}
166
168{
171
172 uint1024_t c = a & b;
173
174 EXPECT_EQ(c.lo, a.lo & b.lo);
175 EXPECT_EQ(c.hi, a.hi & b.hi);
176}
177
179{
182
183 uint1024_t c = a | b;
184
185 EXPECT_EQ(c.lo, a.lo | b.lo);
186 EXPECT_EQ(c.hi, a.hi | b.hi);
187}
188
190{
193
194 uint1024_t c = a ^ b;
195
196 EXPECT_EQ(c.lo, a.lo ^ b.lo);
197 EXPECT_EQ(c.hi, a.hi ^ b.hi);
198}
199
200TEST(uintx, BitNot)
201{
203
204 uint1024_t c = ~a;
205
206 EXPECT_EQ(c.lo, ~a.lo);
207 EXPECT_EQ(c.hi, ~a.hi);
208}
209
210TEST(uintx, LogicNot)
211{
212 uint1024_t a(1);
213
214 bool b = !a;
215
216 EXPECT_EQ(b, false);
217
218 uint1024_t c(0);
219
220 EXPECT_EQ(!c, true);
221}
222
223TEST(uintx, NotEqual)
224{
225 uint1024_t a(1);
226 uint1024_t b(1);
227 EXPECT_EQ(a != b, false);
228
229 a = uint1024_t(0);
230 EXPECT_EQ(a != b, true);
231}
232
233// We should not be depending on ecc in numeric.
234TEST(uintx, DISABLEDInvmod)
235{
236 /*
237 uint256_t prime_lo = prime_256;
238 uint1024_t prime = uint1024_t(uint512_t(prime_lo));
239 uint256_t target_lo = engine.get_random_uint256();
240 uint1024_t target = uint1024_t(uint512_t(target_lo));
241 uint256_t inverse = uint256_t(uint512_t(target.invmod(prime)));
242
243 uint256_t expected = uint256_t(fr(target_lo).invert());
244 EXPECT_EQ(inverse, expected);
245 */
246}
247
248TEST(uintx, InvmodRegressionCheck)
249{
250 const std::array<uint8_t, 64> _a = { 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x0D, 0x6A, 0x2B, 0x19, 0x52,
251 0x2D, 0xF7, 0xAF, 0xC7, 0x95, 0x68, 0x22, 0xD7, 0xF2, 0x21, 0xA3, 0x00, 0x00,
252 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
253 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
254 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
255
256 const std::array<uint8_t, 64> _b = { 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x5D, 0x32, 0xDA, 0x10,
257 0x4F, 0x1D, 0xD6, 0xCA, 0x50, 0x56, 0x11, 0x18, 0x18, 0xC2, 0xD4, 0x6C, 0x70,
258 0x60, 0xD9, 0xB8, 0xFA, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
259 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE2, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
260 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xFF, 0xFF };
261
262 const std::array<uint8_t, 64> expected_result = {
263 0x9F, 0x2F, 0xAA, 0x7B, 0xD7, 0x5A, 0x99, 0x56, 0x04, 0x68, 0x6C, 0x9D, 0xD8, 0x47, 0x6B, 0x52,
264 0xF0, 0x10, 0xD2, 0xA8, 0x62, 0x96, 0x60, 0x68, 0xBE, 0x18, 0x21, 0xA1, 0xCA, 0x6F, 0x41, 0x9C,
265 0x37, 0x42, 0x2F, 0xA3, 0x1B, 0x41, 0x7B, 0xAA, 0xEE, 0x6D, 0x9E, 0x03, 0x78, 0x71, 0xEF, 0xCF,
266 0x90, 0x85, 0xEF, 0x17, 0x59, 0xC4, 0xEE, 0x24, 0x80, 0xDE, 0x7A, 0x58, 0xA5, 0x42, 0x8F, 0x97,
267 };
268
269 std::array<uint8_t, 64> _res;
270
271 uint512_t a;
272 uint512_t b;
273
274 memcpy(a.lo.data, &_a[0], 32);
275 memcpy(a.hi.data, &_a[0] + 32, 32);
276
277 memcpy(b.lo.data, &_b[0], 32);
278 memcpy(b.hi.data, &_b[0] + 32, 32);
279 const auto res = a.invmod(b);
280 memcpy(&_res[0], res.lo.data, 32);
281 memcpy(&_res[0] + 32, res.hi.data, 32);
282
283 EXPECT_EQ(memcmp(&_res[0], &expected_result[0], sizeof(expected_result)), 0);
284}
285TEST(uintx, DISABLEDRInv)
286{
287 /*
288 uint512_t r{ 0, 1 };
289 // -(1/q) mod r
290 uint512_t q{ -prime_256, 0 };
291 uint256_t q_inv = q.invmod(r).lo;
292 uint64_t result = q_inv.data[0];
293 EXPECT_EQ(result, Bn254FrParams::r_inv);
294 */
295}
296
297TEST(uintx, BarrettReductionRegression)
298{
299 // Test specific modulus and self values that may cause issues
300 constexpr uint256_t modulus{ "0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff" };
301
302 // Test case 1: self = 0xffffffff0000000000000000000000000000000000000000003a000000000000
303 // This is a 256-bit value, so we need to construct it as a single uint256_t
304 constexpr uint256_t self_value{ "0xffffffff0000000000000000000000000000000000000000003a000000000000" };
305 uint512_t self(self_value);
306 self = self << 256;
307 const auto [quotient_result, remainder_result] = self.barrett_reduction<modulus>();
308 const auto [quotient_expected, remainder_expected] = self.divmod_base(uint512_t(modulus));
309 EXPECT_EQ(quotient_result, quotient_expected);
310 EXPECT_EQ(remainder_result, remainder_expected);
311}
uint512_t get_random_uint512()
Definition engine.hpp:38
uint1024_t get_random_uint1024()
Definition engine.hpp:46
std::pair< uintx, uintx > divmod_base(const uintx &b) const
bool get_bit(uint64_t bit_index) const
std::pair< uintx, uintx > barrett_reduction() const
FF a
FF b
bool expected_result
numeric::RNG & engine
uintx< uint256_t > uint512_t
Definition uintx.hpp:307
RNG & get_debug_randomness(bool reset, std::uint_fast64_t seed)
Definition engine.cpp:190
uintx< uint512_t > uint1024_t
Definition uintx.hpp:309
Entry point for Barretenberg command-line interface.
TEST(MegaCircuitBuilder, CopyConstructor)