Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
secp256k1.test.cpp
Go to the documentation of this file.
1#include "secp256k1.hpp"
4#include <gtest/gtest.h>
5
6using namespace bb;
7namespace {
9
10constexpr uint256_t test_fq_mod(secp256k1::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(secp256k1, 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 secp256k1::fq a{ a_raw.data[0], a_raw.data[1], a_raw.data[2], a_raw.data[3] };
33 secp256k1::fq b{ b_raw.data[0], b_raw.data[1], b_raw.data[2], b_raw.data[3] };
34
35 secp256k1::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(secp256k1, 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 secp256k1::fq a{ a_raw.data[0], a_raw.data[1], a_raw.data[2], a_raw.data[3] };
54 secp256k1::fq b{ b_raw.data[0], b_raw.data[1], b_raw.data[2], b_raw.data[3] };
55
56 secp256k1::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(secp256k1, 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 secp256k1::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(secp256k1, 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 secp256k1::fq b(a_raw);
95 uint256_t c(b);
96 EXPECT_EQ(a_raw, c);
97 }
98}
99
100TEST(secp256k1, 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 secp256k1::fq a(a_raw);
108 secp256k1::fq b(b_raw);
109 secp256k1::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(secp256k1, 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 secp256k1::fq a(a_raw);
128 secp256k1::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(secp256k1, SqrtRandom)
139{
140 size_t n = 1;
141 for (size_t i = 0; i < n; ++i) {
143 auto [is_sqr, root] = input.sqrt();
144 secp256k1::fq root_test = root.sqr();
145 EXPECT_EQ(root_test, input);
146 }
147}
148
149TEST(secp256k1, TestArithmetic)
150{
153
154 secp256k1::fq c = (a + b) * (a - b);
155 secp256k1::fq d = a.sqr() - b.sqr();
156 EXPECT_EQ(c, d);
157}
158
159TEST(secp256k1, GeneratorOnCurve)
160{
162 EXPECT_EQ(result.on_curve(), true);
163}
164
165TEST(secp256k1, RandomElement)
166{
167 secp256k1::g1::element result = secp256k1::g1::element::random_element();
168 EXPECT_EQ(result.on_curve(), true);
169}
170
171TEST(secp256k1, RandomAffineElement)
172{
173 secp256k1::g1::affine_element result = secp256k1::g1::element::random_element();
174 EXPECT_EQ(result.on_curve(), true);
175}
176
177TEST(secp256k1, Eq)
178{
179 secp256k1::g1::element a = secp256k1::g1::element::random_element();
180 secp256k1::g1::element b = a.normalize();
181
182 EXPECT_EQ(a == b, true);
183 EXPECT_EQ(a == a, true);
184
185 b.self_set_infinity();
186
187 EXPECT_EQ(a == b, false);
188 secp256k1::g1::element c = secp256k1::g1::element::random_element();
189
190 EXPECT_EQ(a == c, false);
191
192 a.self_set_infinity();
193
194 EXPECT_EQ(a == b, true);
195}
196
197TEST(secp256k1, CheckGroupModulus)
198{
199 // secp256k1::g1::affine_element expected = secp256k1::g1::affine_one;
200 secp256k1::fr exponent = -secp256k1::fr(1);
201 secp256k1::g1::element result = secp256k1::g1::one * exponent;
202 result += secp256k1::g1::one;
203 result += secp256k1::g1::one;
204 EXPECT_EQ(result.on_curve(), true);
205 EXPECT_EQ(result == secp256k1::g1::one, true);
206}
207
208TEST(secp256k1, AddExceptionTestInfinity)
209{
210 secp256k1::g1::element lhs = secp256k1::g1::element::random_element();
213
214 rhs = -lhs;
215
216 result = lhs + rhs;
217
218 EXPECT_EQ(result.is_point_at_infinity(), true);
219
221 rhs_b = rhs;
222 rhs_b.self_set_infinity();
223
224 result = lhs + rhs_b;
225
226 EXPECT_EQ(lhs == result, true);
227
228 lhs.self_set_infinity();
229 result = lhs + rhs;
230
231 EXPECT_EQ(rhs == result, true);
232}
233
234TEST(secp256k1, AddExceptionTestDbl)
235{
236 secp256k1::g1::element lhs = secp256k1::g1::element::random_element();
238 rhs = lhs;
239
241 secp256k1::g1::element expected;
242
243 result = lhs + rhs;
244 expected = lhs.dbl();
245
246 EXPECT_EQ(result == expected, true);
247}
248
249TEST(secp256k1, AddDblConsistency)
250{
251 secp256k1::g1::element a = secp256k1::g1::element::random_element();
252 secp256k1::g1::element b = secp256k1::g1::element::random_element();
253
256 secp256k1::g1::element add_result;
257 secp256k1::g1::element dbl_result;
258
259 c = a + b;
260 b = -b;
261 d = a + b;
262
263 add_result = c + d;
264 dbl_result = a.dbl();
265
266 EXPECT_EQ(add_result == dbl_result, true);
267}
268
269TEST(secp256k1, AddDblConsistencyRepeated)
270{
271 secp256k1::g1::element a = secp256k1::g1::element::random_element();
276
278 secp256k1::g1::element expected;
279
280 b = a.dbl(); // b = 2a
281 c = b.dbl(); // c = 4a
282
283 d = a + b; // d = 3a
284 e = a + c; // e = 5a
285 result = d + e; // result = 8a
286
287 expected = c.dbl(); // expected = 8a
288
289 EXPECT_EQ(result == expected, true);
290}
291
292TEST(secp256k1, MixedAddExceptionTestInfinity)
293{
295 secp256k1::g1::affine_element rhs = secp256k1::g1::element::random_element();
296 secp256k1::fq::__copy(rhs.x, lhs.x);
297 lhs.y = -rhs.y;
298
300 result = lhs + rhs;
301
302 EXPECT_EQ(result.is_point_at_infinity(), true);
303
304 lhs.self_set_infinity();
305 result = lhs + rhs;
307 rhs_c = secp256k1::g1::element(rhs);
308
309 EXPECT_EQ(rhs_c == result, true);
310}
311
312TEST(secp256k1, MixedAddExceptionTestDbl)
313{
314 secp256k1::g1::affine_element rhs = secp256k1::g1::element::random_element();
316 lhs = secp256k1::g1::element(rhs);
317
319 secp256k1::g1::element expected;
320 result = lhs + rhs;
321
322 expected = lhs.dbl();
323
324 EXPECT_EQ(result == expected, true);
325}
326
327TEST(secp256k1, AddMixedAddConsistencyCheck)
328{
329 secp256k1::g1::affine_element rhs = secp256k1::g1::element::random_element();
330 secp256k1::g1::element lhs = secp256k1::g1::element::random_element();
332 rhs_b = secp256k1::g1::element(rhs);
333
334 secp256k1::g1::element add_result;
335 secp256k1::g1::element mixed_add_result;
336 add_result = lhs + rhs_b;
337 mixed_add_result = lhs + rhs;
338
339 EXPECT_EQ(add_result == mixed_add_result, true);
340}
341
342TEST(secp256k1, OnCurve)
343{
344 for (size_t i = 0; i < 100; ++i) {
345 secp256k1::g1::element test = secp256k1::g1::element::random_element();
346 EXPECT_EQ(test.on_curve(), true);
347 secp256k1::g1::affine_element affine_test = secp256k1::g1::element::random_element();
348 EXPECT_EQ(affine_test.on_curve(), true);
349 }
350}
351TEST(secp256k1, BatchNormalize)
352{
353 size_t num_points = 2;
354 std::vector<secp256k1::g1::element> points(num_points);
355 std::vector<secp256k1::g1::element> normalized(num_points);
356 for (size_t i = 0; i < num_points; ++i) {
357 secp256k1::g1::element a = secp256k1::g1::element::random_element();
358 secp256k1::g1::element b = secp256k1::g1::element::random_element();
359 points[i] = a + b;
360 normalized[i] = points[i];
361 }
362 secp256k1::g1::element::batch_normalize(&normalized[0], num_points);
363
364 for (size_t i = 0; i < num_points; ++i) {
365 secp256k1::fq zz;
366 secp256k1::fq zzz;
367 secp256k1::fq result_x;
368 secp256k1::fq result_y;
369 zz = points[i].z.sqr();
370 zzz = points[i].z * zz;
371 result_x = normalized[i].x * zz;
372 result_y = normalized[i].y * zzz;
373
374 EXPECT_EQ((result_x == points[i].x), true);
375 EXPECT_EQ((result_y == points[i].y), true);
376 }
377}
378
379TEST(secp256k1, GroupExponentiationZeroAndOne)
380{
382
383 EXPECT_EQ(result.is_point_at_infinity(), true);
384
386
387 EXPECT_EQ(result == secp256k1::g1::affine_one, true);
388}
389
390TEST(secp256k1, GroupExponentiationConsistencyCheck)
391{
394
396 c = a * b;
397
399 secp256k1::g1::affine_element result = input * a;
400 result = result * b;
401
402 secp256k1::g1::affine_element expected = input * c;
403
404 EXPECT_EQ(result == expected, true);
405}
406
407TEST(secp256k1, DeriveGenerators)
408{
409 constexpr size_t num_generators = 128;
410 auto result = secp256k1::g1::derive_generators("test generators", num_generators);
411
412 const auto is_unique = [&result](const secp256k1::g1::affine_element& y, const size_t j) {
413 for (size_t i = 0; i < result.size(); ++i) {
414 if ((i != j) && result[i] == y) {
415 return false;
416 }
417 }
418 return true;
419 };
420
421 for (size_t k = 0; k < num_generators; ++k) {
422 EXPECT_EQ(is_unique(result[k], k), true);
423 EXPECT_EQ(result[k].on_curve(), true);
424 }
425}
426
427TEST(secp256k1, CheckPrecomputedGenerators)
428{
429 ASSERT_TRUE((bb::check_precomputed_generators<secp256k1::g1, "biggroup offset generator", 1UL>()));
430 ASSERT_TRUE((bb::check_precomputed_generators<secp256k1::g1, "biggroup table offset generator", 1UL>()));
431}
432
433TEST(secp256k1, GetEndomorphismScalars)
434{
435 for (size_t i = 0; i < 2048; i++) {
437 secp256k1::fr k1 = 0;
438 secp256k1::fr k2 = 0;
439
441 bool k1_neg = false;
442 bool k2_neg = false;
443
445 k2 = -k2;
446 k2_neg = true;
447 }
448
449 EXPECT_LT(k1.uint256_t_no_montgomery_conversion().get_msb(), 129ULL);
450 EXPECT_LT(k2.uint256_t_no_montgomery_conversion().get_msb(), 129ULL);
451
452 if (k1_neg) {
453 k1 = -k1;
454 }
455 if (k2_neg) {
456 k2 = -k2;
457 }
458
461
463 secp256k1::fr expected = k1 - k2 * beta;
464
465 expected.self_from_montgomery_form();
466 EXPECT_EQ(k, expected);
467 if (k != expected) {
468 break;
469 }
470 }
471}
472
473TEST(secp256k1, TestEndomorphismScalars)
474{
476 secp256k1::fr k1 = 0;
477 secp256k1::fr k2 = 0;
478
480 bool k1_neg = false;
481 bool k2_neg = false;
482
484 k1 = -k1;
485 k1_neg = true;
486 }
488 k2 = -k2;
489 k2_neg = true;
490 }
491
492 EXPECT_LT(k1.uint256_t_no_montgomery_conversion().get_msb(), 129ULL);
493 EXPECT_LT(k2.uint256_t_no_montgomery_conversion().get_msb(), 129ULL);
494
495 if (k1_neg) {
496 k1 = -k1;
497 }
498 if (k2_neg) {
499 k2 = -k2;
500 }
503 static const uint256_t secp256k1_const_lambda{
504 0xDF02967C1B23BD72ULL, 0x122E22EA20816678UL, 0xA5261C028812645AULL, 0x5363AD4CC05C30E0ULL
505 };
506
507 secp256k1::fr expected = k1 - k2 * secp256k1_const_lambda;
508
509 expected.self_from_montgomery_form();
510 EXPECT_EQ(k, expected);
511}
512
513TEST(secp256k1, NegAndSelfNeg0CmpRegression)
514{
515 secp256k1::fq a = 0;
516 secp256k1::fq a_neg = -a;
517 EXPECT_EQ((a == a_neg), true);
518 a = 0;
519 a_neg = 0;
520 a_neg.self_neg();
521 EXPECT_EQ((a == a_neg), true);
522}
523
524TEST(secp256k1, MontgomeryMulBigBug)
525{
526 secp256k1::fq a(uint256_t{ 0xfffffffe630dc02f, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff });
527 secp256k1::fq a_sqr = a.sqr();
528 secp256k1::fq expected(uint256_t{ 0x60381e557e100000, 0x0, 0x0, 0x0 });
529 EXPECT_EQ((a_sqr == expected), true);
530}
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
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
static std::vector< affine_element > derive_generators(const std::vector< uint8_t > &domain_separator_bytes, const size_t num_generators, const size_t starting_index=0)
Derives generator points via hash-to-curve.
Definition group.hpp:87
virtual uint256_t get_random_uint256()=0
constexpr uint64_t get_msb() const
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
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
General class for prime fields see Prime field documentation["field documentation"] for general imple...
static constexpr field cube_root_of_unity()
static constexpr field one()
static void split_into_endomorphism_scalars(const field &k, field &k1, field &k2)
BB_INLINE constexpr void self_neg() &noexcept
static field random_element(numeric::RNG *engine=nullptr) noexcept
BB_INLINE constexpr field sqr() const noexcept
constexpr uint256_t uint256_t_no_montgomery_conversion() const noexcept
constexpr std::pair< bool, field > sqrt() const noexcept
Compute square root of the field element.
static BB_INLINE void __copy(const field &a, field &r) noexcept
BB_INLINE constexpr void self_from_montgomery_form() &noexcept
BB_INLINE constexpr void self_to_montgomery_form() &noexcept
static constexpr field zero()
static constexpr uint64_t modulus_0
Definition secp256k1.hpp:21
static constexpr uint64_t modulus_1
Definition secp256k1.hpp:22
static constexpr uint64_t modulus_2
Definition secp256k1.hpp:23
static constexpr uint64_t modulus_3
Definition secp256k1.hpp:24