Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
secp256r1.test.cpp
Go to the documentation of this file.
1#include "secp256r1.hpp"
4#include <gtest/gtest.h>
5
6using namespace bb;
7namespace {
9
10constexpr uint256_t test_fq_mod(secp256r1::FqParams::modulus_0,
14
15uint256_t get_fq_element()
16{
18 while (res >= test_fq_mod) {
19 res -= test_fq_mod;
20 }
21 return res;
22}
23} // namespace
24
25TEST(secp256r1, TestAdd)
26{
27 const size_t n = 100;
28 for (size_t i = 0; i < n; ++i) {
29 uint256_t a_raw = get_fq_element();
30 uint256_t b_raw = get_fq_element();
31
32 secp256r1::fq a{ a_raw.data[0], a_raw.data[1], a_raw.data[2], a_raw.data[3] };
33 secp256r1::fq b{ b_raw.data[0], b_raw.data[1], b_raw.data[2], b_raw.data[3] };
34
35 secp256r1::fq c = a + b;
36
37 uint256_t expected = a_raw + b_raw;
38 if (expected < a_raw) {
39 expected -= test_fq_mod;
40 }
41 uint256_t result{ c.data[0], c.data[1], c.data[2], c.data[3] };
42 EXPECT_EQ(result, expected);
43 }
44}
45
46TEST(secp256r1, TestSub)
47{
48 const size_t n = 100;
49 for (size_t i = 0; i < n; ++i) {
50 uint256_t a_raw = get_fq_element();
51 uint256_t b_raw = get_fq_element();
52
53 secp256r1::fq a{ a_raw.data[0], a_raw.data[1], a_raw.data[2], a_raw.data[3] };
54 secp256r1::fq b{ b_raw.data[0], b_raw.data[1], b_raw.data[2], b_raw.data[3] };
55
56 secp256r1::fq c = a - b;
57
58 uint256_t expected = a_raw - b_raw;
59 if (expected > a_raw) {
60 expected += test_fq_mod;
61 }
62 uint256_t result{ c.data[0], c.data[1], c.data[2], c.data[3] };
63 EXPECT_EQ(result, expected);
64 }
65}
66
67TEST(secp256r1, TestToMontgomeryForm)
68{
69 const size_t n = 10;
70 for (size_t i = 0; i < n; ++i) {
71 uint256_t a_raw = get_fq_element();
72 secp256r1::fq montgomery_result(a_raw);
73
74#if defined(__SIZEOF_INT128__) && !defined(__wasm__)
75 constexpr uint512_t R = uint512_t(0, 1);
76#else
77 const uint512_t R = (uint512_t(1) << (29 * 9)) % uint512_t(test_fq_mod);
78#endif
79 uint512_t aR = uint512_t(a_raw) * R;
80 uint256_t expected = (aR % uint512_t(test_fq_mod)).lo;
81
82 uint256_t result{
83 montgomery_result.data[0], montgomery_result.data[1], montgomery_result.data[2], montgomery_result.data[3]
84 };
85 EXPECT_EQ(result, expected);
86 }
87}
88
89TEST(secp256r1, TestFromMontgomeryForm)
90{
91 const size_t n = 100;
92 for (size_t i = 0; i < n; ++i) {
93 uint256_t a_raw = get_fq_element();
94 secp256r1::fq b(a_raw);
95 uint256_t c(b);
96 EXPECT_EQ(a_raw, c);
97 }
98}
99
100TEST(secp256r1, TestMul)
101{
102 const size_t n = 10;
103 for (size_t i = 0; i < n; ++i) {
104 uint256_t a_raw = get_fq_element();
105 uint256_t b_raw = get_fq_element();
106
107 secp256r1::fq a(a_raw);
108 secp256r1::fq b(b_raw);
109 secp256r1::fq c = (a * b);
110
111 uint1024_t a_1024((uint512_t(a_raw)));
112 uint1024_t b_1024((uint512_t(b_raw)));
113 uint1024_t c_1024 = a_1024 * b_1024;
114 uint1024_t cmod = c_1024 % uint1024_t(uint512_t(test_fq_mod));
115 uint256_t expected = cmod.lo.lo;
116 uint256_t result(c);
117 EXPECT_EQ(result, expected);
118 }
119}
120
121TEST(secp256r1, TestSqr)
122{
123 const size_t n = 10;
124 for (size_t i = 0; i < n; ++i) {
125 uint256_t a_raw = get_fq_element();
126
127 secp256r1::fq a(a_raw);
128 secp256r1::fq c = a.sqr();
129
130 uint512_t c_raw = uint512_t(a_raw) * uint512_t(a_raw);
131 c_raw = c_raw % uint512_t(test_fq_mod);
132 uint256_t expected = c_raw.lo;
133 uint256_t result(c);
134 EXPECT_EQ(result, expected);
135 }
136}
137
138TEST(secp256r1, TestArithmetic)
139{
142
143 secp256r1::fq c = (a + b) * (a - b);
144 secp256r1::fq d = a.sqr() - b.sqr();
145 EXPECT_EQ(c, d);
146}
147
148TEST(secp256r1, GeneratorOnCurve)
149{
151 EXPECT_EQ(result.on_curve(), true);
152}
153
154TEST(secp256r1, RandomElement)
155{
156 secp256r1::g1::element result = secp256r1::g1::element::random_element();
157 EXPECT_EQ(result.on_curve(), true);
158}
159
160TEST(secp256r1, RandomAffineElement)
161{
162 secp256r1::g1::affine_element result = secp256r1::g1::element::random_element();
163 EXPECT_EQ(result.on_curve(), true);
164}
165
166TEST(secp256r1, Eq)
167{
168 secp256r1::g1::element a = secp256r1::g1::element::random_element();
170
171 EXPECT_EQ(a == b, true);
172 EXPECT_EQ(a == a, true);
173
174 b.self_set_infinity();
175
176 EXPECT_EQ(a == b, false);
177 secp256r1::g1::element c = secp256r1::g1::element::random_element();
178
179 EXPECT_EQ(a == c, false);
180
181 a.self_set_infinity();
182
183 EXPECT_EQ(a == b, true);
184}
185
186TEST(secp256r1, CheckGroupModulus)
187{
188 // secp256r1::g1::affine_element expected = secp256r1::g1::affine_one;
189 secp256r1::fr exponent = -secp256r1::fr(1);
190 secp256r1::g1::element result = secp256r1::g1::one * exponent;
191 result += secp256r1::g1::one;
192 result += secp256r1::g1::one;
193 EXPECT_EQ(result.on_curve(), true);
194 EXPECT_EQ(result == secp256r1::g1::one, true);
195}
196
197TEST(secp256r1, AddExceptionTestInfinity)
198{
199 secp256r1::g1::element lhs = secp256r1::g1::element::random_element();
202
203 rhs = -lhs;
204
205 result = lhs + rhs;
206
207 EXPECT_EQ(result.is_point_at_infinity(), true);
208
210 rhs_b = rhs;
211 rhs_b.self_set_infinity();
212
213 result = lhs + rhs_b;
214
215 EXPECT_EQ(lhs == result, true);
216
217 lhs.self_set_infinity();
218 result = lhs + rhs;
219
220 EXPECT_EQ(rhs == result, true);
221}
222
223TEST(secp256r1, AddExceptionTestDbl)
224{
225 secp256r1::g1::element lhs = secp256r1::g1::element::random_element();
227 rhs = lhs;
228
230 secp256r1::g1::element expected;
231
232 result = lhs + rhs;
233 expected = lhs.dbl();
234
235 EXPECT_EQ(result == expected, true);
236}
237
238TEST(secp256r1, AddDblConsistency)
239{
241 secp256r1::g1::element b = a.dbl(); // 2P
242
243 secp256r1::g1::element c = b.dbl(); // 4P
244 c = c.dbl(); // 8P
245
246 secp256r1::g1::element d = a + b; // 3P
247 d = d + b; // 5P
248 d = d + a; // 6P
249 d = d + a; // 7P
250 d = d + a; // 8P
251 EXPECT_EQ(c, d);
252}
253
254TEST(secp256r1, AddDblConsistencyRepeated)
255{
256 secp256r1::g1::element a = secp256r1::g1::element::random_element();
261
263 secp256r1::g1::element expected;
264
265 b = a.dbl(); // b = 2a
266 c = b.dbl(); // c = 4a
267
268 d = a + b; // d = 3a
269 e = a + c; // e = 5a
270 result = d + e; // result = 8a
271
272 expected = c.dbl(); // expected = 8a
273
274 EXPECT_EQ(result == expected, true);
275}
276
277TEST(secp256r1, MixedAddExceptionTestInfinity)
278{
280 secp256r1::g1::affine_element rhs = secp256r1::g1::element::random_element();
281 secp256r1::fq::__copy(rhs.x, lhs.x);
282 lhs.y = -rhs.y;
283
285 result = lhs + rhs;
286
287 EXPECT_EQ(result.is_point_at_infinity(), true);
288
289 lhs.self_set_infinity();
290 result = lhs + rhs;
292 rhs_c = secp256r1::g1::element(rhs);
293
294 EXPECT_EQ(rhs_c == result, true);
295}
296
297TEST(secp256r1, MixedAddExceptionTestDbl)
298{
299 secp256r1::g1::affine_element rhs = secp256r1::g1::element::random_element();
301 lhs = secp256r1::g1::element(rhs);
302
304 secp256r1::g1::element expected;
305 result = lhs + rhs;
306
307 expected = lhs.dbl();
308
309 EXPECT_EQ(result == expected, true);
310}
311
312TEST(secp256r1, AddMixedAddConsistencyCheck)
313{
314 secp256r1::g1::affine_element rhs = secp256r1::g1::element::random_element();
315 secp256r1::g1::element lhs = secp256r1::g1::element::random_element();
317 rhs_b = secp256r1::g1::element(rhs);
318
319 secp256r1::g1::element add_result;
320 secp256r1::g1::element mixed_add_result;
321 add_result = lhs + rhs_b;
322 mixed_add_result = lhs + rhs;
323
324 EXPECT_EQ(add_result == mixed_add_result, true);
325}
326
327TEST(secp256r1, OnCurve)
328{
329 for (size_t i = 0; i < 100; ++i) {
330 secp256r1::g1::element test = secp256r1::g1::element::random_element();
331 EXPECT_EQ(test.on_curve(), true);
332 secp256r1::g1::affine_element affine_test = secp256r1::g1::element::random_element();
333 EXPECT_EQ(affine_test.on_curve(), true);
334 }
335}
336TEST(secp256r1, BatchNormalize)
337{
338 size_t num_points = 2;
339 std::vector<secp256r1::g1::element> points(num_points);
340 std::vector<secp256r1::g1::element> normalized(num_points);
341 for (size_t i = 0; i < num_points; ++i) {
342 secp256r1::g1::element a = secp256r1::g1::element::random_element();
343 secp256r1::g1::element b = secp256r1::g1::element::random_element();
344 points[i] = a + b;
345 normalized[i] = points[i];
346 }
347 secp256r1::g1::element::batch_normalize(&normalized[0], num_points);
348
349 for (size_t i = 0; i < num_points; ++i) {
350 secp256r1::fq zz;
351 secp256r1::fq zzz;
352 secp256r1::fq result_x;
353 secp256r1::fq result_y;
354 zz = points[i].z.sqr();
355 zzz = points[i].z * zz;
356 result_x = normalized[i].x * zz;
357 result_y = normalized[i].y * zzz;
358
359 EXPECT_EQ((result_x == points[i].x), true);
360 EXPECT_EQ((result_y == points[i].y), true);
361 }
362}
363
364TEST(secp256r1, GroupExponentiationZeroAndOne)
365{
367
368 EXPECT_EQ(result.is_point_at_infinity(), true);
370
371 EXPECT_EQ(result.is_point_at_infinity(), true);
372 EXPECT_NE(pif, secp256r1::g1::one);
373
375
376 EXPECT_EQ(result == secp256r1::g1::affine_one, true);
377}
378
379TEST(secp256r1, GroupExponentiationConsistencyCheck)
380{
383
385 c = a * b;
386
388 secp256r1::g1::affine_element result = input * a;
389 result = result * b;
390
391 secp256r1::g1::affine_element expected = input * c;
392
393 EXPECT_EQ(result == expected, true);
394}
395
401TEST(secp256r1, AdditionSubtractionRegressionCheck)
402{
403 secp256r1::fq fq1(uint256_t{ 0xfffffe0000000200, 0x200fffff9ff, 0xfffffbfffffffe00, 0xfffffbff00000400 });
404 secp256r1::fq fq2(uint256_t{ 0xfffffe0000000200, 0x200fffff9ff, 0xfffffbfffffffe00, 0xfffffbff00000400 });
405 secp256r1::fq fq3(0);
406 secp256r1::fq fq4(0);
408 fq1 += secp256r1::fq(2);
409
410 fq3 -= fq1;
411 fq4 -= fq2;
412 EXPECT_EQ(fq1 + fq1, fq2 + fq2);
413 EXPECT_EQ(fq3, fq4);
414}
415
416/* TODO (#LARGE_MODULUS_AFFINE_POINT_COMPRESSION): Rewrite this test after designing point compression for p>2^255
417TEST(secp256r1, derive_generators)
418{
419 constexpr size_t num_generators = 128;
420 auto result = secp256r1::g1::derive_generators<num_generators>();
421
422 const auto is_unique = [&result](const secp256r1::g1::affine_element& y, const size_t j) {
423 for (size_t i = 0; i < result.size(); ++i) {
424 if ((i != j) && result[i] == y) {
425 return false;
426 }
427 }
428 return true;
429 };
430
431 for (size_t k = 0; k < num_generators; ++k) {
432 EXPECT_EQ(is_unique(result[k], k), true);
433 EXPECT_EQ(result[k].on_curve(), true);
434 }
435}
436TEST(secp256r1, check_compression_constructor)
437{
438 secp256r1::g1::affine_element el(uint256_t(10));
439 std::cout << "Affine element: " << el << std::endl;
440}**/
441
442#if defined(__SIZEOF_INT128__) && !defined(__wasm__)
443TEST(secp256r1, MontgomeryMulBigBug)
444{
446 a.data[0] = 0xC5BF4F6AFF993D09;
447 a.data[1] = 0xA3361BDA67E62E0E;
448 a.data[2] = 0xAAAAAAAAAAAAAAAA;
449 a.data[3] = 0xFFFFFFFFE38E38E3;
450 secp256r1::fr a_sqr = a.sqr();
451 secp256r1::fr expected(uint256_t{ 0x57abc6aa0349c084, 0x65b21b232a4cb7a5, 0x5ba781948b0fcd6e, 0xd6e9e0644bda12f7 });
452 EXPECT_EQ((a_sqr == expected), true);
453}
454#endif
455
456TEST(secp256r1, CheckPrecomputedGenerators)
457{
458 ASSERT_TRUE((bb::check_precomputed_generators<secp256r1::g1, "biggroup offset generator", 1UL>()));
459 ASSERT_TRUE((bb::check_precomputed_generators<secp256r1::g1, "biggroup table offset generator", 1UL>()));
460}
461
462// Hacky: wasm does not properly find main() from gmock_main.
463// We only want to run wasm tests specifically for ecc ops as our field handling is different.
464// We need to make sure the hardcoded generators make sense.
465// As this is our narrow focus, we hack this so ecc_tests can run.
466#ifdef __wasm__
467GTEST_API_ int main(int argc, char** argv)
468{
469 testing::InitGoogleTest(&argc, argv);
470 return RUN_ALL_TESTS();
471}
472#endif
int main(int argc, char *argv[])
Definition main.cpp:3
constexpr bool is_point_at_infinity() const noexcept
constexpr bool on_curve() const noexcept
element class. Implements ecc group arithmetic using Jacobian coordinates See https://hyperelliptic....
Definition element.hpp:33
constexpr element dbl() const noexcept
constexpr element normalize() const noexcept
BB_INLINE constexpr bool on_curve() const noexcept
BB_INLINE constexpr void self_set_infinity() noexcept
BB_INLINE constexpr bool is_point_at_infinity() const noexcept
static constexpr element one
Definition group.hpp:46
static constexpr affine_element affine_one
Definition group.hpp:48
group_elements::element< Fq, Fr, Params > element
Definition group.hpp:41
virtual uint256_t get_random_uint256()=0
FF a
FF b
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
field< FrParams > fr
field< FqParams > fq
Entry point for Barretenberg command-line interface.
TEST(MegaCircuitBuilder, CopyConstructor)
field2< fq, Bn254Fq2Params > fq2
Definition fq2.hpp:67
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
General class for prime fields see Prime field documentation["field documentation"] for general imple...
static constexpr field one()
static field random_element(numeric::RNG *engine=nullptr) noexcept
BB_INLINE constexpr field sqr() const noexcept
static constexpr uint256_t modulus_minus_two
static BB_INLINE void __copy(const field &a, field &r) noexcept
static constexpr field zero()
static constexpr uint64_t modulus_3
Definition secp256r1.hpp:19
static constexpr uint64_t modulus_2
Definition secp256r1.hpp:18
static constexpr uint64_t modulus_0
Definition secp256r1.hpp:16
static constexpr uint64_t modulus_1
Definition secp256r1.hpp:17