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"
3#include <gtest/gtest.h>
4
5using namespace bb;
6namespace {
8
9constexpr uint256_t test_fq_mod(secp256k1::FqParams::modulus_0,
13
14uint256_t get_fq_element()
15{
17 while (res >= test_fq_mod) {
18 res -= test_fq_mod;
19 }
20 return res;
21}
22} // namespace
23
24TEST(secp256k1, TestAdd)
25{
26 const size_t n = 100;
27 for (size_t i = 0; i < n; ++i) {
28 uint256_t a_raw = get_fq_element();
29 uint256_t b_raw = get_fq_element();
30
31 secp256k1::fq a{ a_raw.data[0], a_raw.data[1], a_raw.data[2], a_raw.data[3] };
32 secp256k1::fq b{ b_raw.data[0], b_raw.data[1], b_raw.data[2], b_raw.data[3] };
33
34 secp256k1::fq c = a + b;
35
36 uint256_t expected = a_raw + b_raw;
37 if (expected < a_raw) {
38 expected -= test_fq_mod;
39 }
40 uint256_t result{ c.data[0], c.data[1], c.data[2], c.data[3] };
41 EXPECT_EQ(result, expected);
42 }
43}
44
45TEST(secp256k1, TestSub)
46{
47 const size_t n = 100;
48 for (size_t i = 0; i < n; ++i) {
49 uint256_t a_raw = get_fq_element();
50 uint256_t b_raw = get_fq_element();
51
52 secp256k1::fq a{ a_raw.data[0], a_raw.data[1], a_raw.data[2], a_raw.data[3] };
53 secp256k1::fq b{ b_raw.data[0], b_raw.data[1], b_raw.data[2], b_raw.data[3] };
54
55 secp256k1::fq c = a - b;
56
57 uint256_t expected = a_raw - b_raw;
58 if (expected > a_raw) {
59 expected += test_fq_mod;
60 }
61 uint256_t result{ c.data[0], c.data[1], c.data[2], c.data[3] };
62 EXPECT_EQ(result, expected);
63 }
64}
65
66TEST(secp256k1, TestToMontgomeryForm)
67{
68 const size_t n = 10;
69 for (size_t i = 0; i < n; ++i) {
70 uint256_t a_raw = get_fq_element();
71 secp256k1::fq montgomery_result(a_raw);
72
73#if defined(__SIZEOF_INT128__) && !defined(__wasm__)
74 constexpr uint512_t R = uint512_t(0, 1);
75#else
76 const uint512_t R = (uint512_t(1) << (29 * 9)) % uint512_t(test_fq_mod);
77#endif
78 uint512_t aR = uint512_t(a_raw) * R;
79 uint256_t expected = (aR % uint512_t(test_fq_mod)).lo;
80
81 uint256_t result{
82 montgomery_result.data[0], montgomery_result.data[1], montgomery_result.data[2], montgomery_result.data[3]
83 };
84 EXPECT_EQ(result, expected);
85 }
86}
87
88TEST(secp256k1, TestFromMontgomeryForm)
89{
90 const size_t n = 100;
91 for (size_t i = 0; i < n; ++i) {
92 uint256_t a_raw = get_fq_element();
93 secp256k1::fq b(a_raw);
94 uint256_t c(b);
95 EXPECT_EQ(a_raw, c);
96 }
97}
98
99TEST(secp256k1, TestMul)
100{
101 const size_t n = 10;
102 for (size_t i = 0; i < n; ++i) {
103 uint256_t a_raw = get_fq_element();
104 uint256_t b_raw = get_fq_element();
105
106 secp256k1::fq a(a_raw);
107 secp256k1::fq b(b_raw);
108 secp256k1::fq c = (a * b);
109
110 uint1024_t a_1024((uint512_t(a_raw)));
111 uint1024_t b_1024((uint512_t(b_raw)));
112 uint1024_t c_1024 = a_1024 * b_1024;
113 uint1024_t cmod = c_1024 % uint1024_t(uint512_t(test_fq_mod));
114 uint256_t expected = cmod.lo.lo;
115 uint256_t result(c);
116 EXPECT_EQ(result, expected);
117 }
118}
119
120TEST(secp256k1, TestSqr)
121{
122 const size_t n = 10;
123 for (size_t i = 0; i < n; ++i) {
124 uint256_t a_raw = get_fq_element();
125
126 secp256k1::fq a(a_raw);
127 secp256k1::fq c = a.sqr();
128
129 uint512_t c_raw = uint512_t(a_raw) * uint512_t(a_raw);
130 c_raw = c_raw % uint512_t(test_fq_mod);
131 uint256_t expected = c_raw.lo;
132 uint256_t result(c);
133 EXPECT_EQ(result, expected);
134 }
135}
136
137TEST(secp256k1, SqrtRandom)
138{
139 size_t n = 1;
140 for (size_t i = 0; i < n; ++i) {
142 auto [is_sqr, root] = input.sqrt();
143 secp256k1::fq root_test = root.sqr();
144 EXPECT_EQ(root_test, input);
145 }
146}
147
148TEST(secp256k1, TestArithmetic)
149{
152
153 secp256k1::fq c = (a + b) * (a - b);
154 secp256k1::fq d = a.sqr() - b.sqr();
155 EXPECT_EQ(c, d);
156}
157
158TEST(secp256k1, GeneratorOnCurve)
159{
161 EXPECT_EQ(result.on_curve(), true);
162}
163
164TEST(secp256k1, RandomElement)
165{
166 secp256k1::g1::element result = secp256k1::g1::element::random_element();
167 EXPECT_EQ(result.on_curve(), true);
168}
169
170TEST(secp256k1, RandomAffineElement)
171{
172 secp256k1::g1::affine_element result = secp256k1::g1::element::random_element();
173 EXPECT_EQ(result.on_curve(), true);
174}
175
176TEST(secp256k1, Eq)
177{
178 secp256k1::g1::element a = secp256k1::g1::element::random_element();
180
181 EXPECT_EQ(a == b, true);
182 EXPECT_EQ(a == a, true);
183
184 b.self_set_infinity();
185
186 EXPECT_EQ(a == b, false);
187 secp256k1::g1::element c = secp256k1::g1::element::random_element();
188
189 EXPECT_EQ(a == c, false);
190
191 a.self_set_infinity();
192
193 EXPECT_EQ(a == b, true);
194}
195
196TEST(secp256k1, CheckGroupModulus)
197{
198 // secp256k1::g1::affine_element expected = secp256k1::g1::affine_one;
199 secp256k1::fr exponent = -secp256k1::fr(1);
200 secp256k1::g1::element result = secp256k1::g1::one * exponent;
201 result += secp256k1::g1::one;
202 result += secp256k1::g1::one;
203 EXPECT_EQ(result.on_curve(), true);
204 EXPECT_EQ(result == secp256k1::g1::one, true);
205}
206
207TEST(secp256k1, AddExceptionTestInfinity)
208{
209 secp256k1::g1::element lhs = secp256k1::g1::element::random_element();
212
213 rhs = -lhs;
214
215 result = lhs + rhs;
216
217 EXPECT_EQ(result.is_point_at_infinity(), true);
218
220 rhs_b = rhs;
221 rhs_b.self_set_infinity();
222
223 result = lhs + rhs_b;
224
225 EXPECT_EQ(lhs == result, true);
226
227 lhs.self_set_infinity();
228 result = lhs + rhs;
229
230 EXPECT_EQ(rhs == result, true);
231}
232
233TEST(secp256k1, AddExceptionTestDbl)
234{
235 secp256k1::g1::element lhs = secp256k1::g1::element::random_element();
237 rhs = lhs;
238
240 secp256k1::g1::element expected;
241
242 result = lhs + rhs;
243 expected = lhs.dbl();
244
245 EXPECT_EQ(result == expected, true);
246}
247
248TEST(secp256k1, AddDblConsistency)
249{
250 secp256k1::g1::element a = secp256k1::g1::element::random_element();
251 secp256k1::g1::element b = secp256k1::g1::element::random_element();
252
255 secp256k1::g1::element add_result;
256 secp256k1::g1::element dbl_result;
257
258 c = a + b;
259 b = -b;
260 d = a + b;
261
262 add_result = c + d;
263 dbl_result = a.dbl();
264
265 EXPECT_EQ(add_result == dbl_result, true);
266}
267
268TEST(secp256k1, AddDblConsistencyRepeated)
269{
270 secp256k1::g1::element a = secp256k1::g1::element::random_element();
275
277 secp256k1::g1::element expected;
278
279 b = a.dbl(); // b = 2a
280 c = b.dbl(); // c = 4a
281
282 d = a + b; // d = 3a
283 e = a + c; // e = 5a
284 result = d + e; // result = 8a
285
286 expected = c.dbl(); // expected = 8a
287
288 EXPECT_EQ(result == expected, true);
289}
290
291TEST(secp256k1, MixedAddExceptionTestInfinity)
292{
294 secp256k1::g1::affine_element rhs = secp256k1::g1::element::random_element();
295 secp256k1::fq::__copy(rhs.x, lhs.x);
296 lhs.y = -rhs.y;
297
299 result = lhs + rhs;
300
301 EXPECT_EQ(result.is_point_at_infinity(), true);
302
303 lhs.self_set_infinity();
304 result = lhs + rhs;
306 rhs_c = secp256k1::g1::element(rhs);
307
308 EXPECT_EQ(rhs_c == result, true);
309}
310
311TEST(secp256k1, MixedAddExceptionTestDbl)
312{
313 secp256k1::g1::affine_element rhs = secp256k1::g1::element::random_element();
315 lhs = secp256k1::g1::element(rhs);
316
318 secp256k1::g1::element expected;
319 result = lhs + rhs;
320
321 expected = lhs.dbl();
322
323 EXPECT_EQ(result == expected, true);
324}
325
326TEST(secp256k1, AddMixedAddConsistencyCheck)
327{
328 secp256k1::g1::affine_element rhs = secp256k1::g1::element::random_element();
329 secp256k1::g1::element lhs = secp256k1::g1::element::random_element();
331 rhs_b = secp256k1::g1::element(rhs);
332
333 secp256k1::g1::element add_result;
334 secp256k1::g1::element mixed_add_result;
335 add_result = lhs + rhs_b;
336 mixed_add_result = lhs + rhs;
337
338 EXPECT_EQ(add_result == mixed_add_result, true);
339}
340
341TEST(secp256k1, OnCurve)
342{
343 for (size_t i = 0; i < 100; ++i) {
344 secp256k1::g1::element test = secp256k1::g1::element::random_element();
345 EXPECT_EQ(test.on_curve(), true);
346 secp256k1::g1::affine_element affine_test = secp256k1::g1::element::random_element();
347 EXPECT_EQ(affine_test.on_curve(), true);
348 }
349}
350TEST(secp256k1, BatchNormalize)
351{
352 size_t num_points = 2;
353 std::vector<secp256k1::g1::element> points(num_points);
354 std::vector<secp256k1::g1::element> normalized(num_points);
355 for (size_t i = 0; i < num_points; ++i) {
356 secp256k1::g1::element a = secp256k1::g1::element::random_element();
357 secp256k1::g1::element b = secp256k1::g1::element::random_element();
358 points[i] = a + b;
359 normalized[i] = points[i];
360 }
361 secp256k1::g1::element::batch_normalize(&normalized[0], num_points);
362
363 for (size_t i = 0; i < num_points; ++i) {
364 secp256k1::fq zz;
365 secp256k1::fq zzz;
366 secp256k1::fq result_x;
367 secp256k1::fq result_y;
368 zz = points[i].z.sqr();
369 zzz = points[i].z * zz;
370 result_x = normalized[i].x * zz;
371 result_y = normalized[i].y * zzz;
372
373 EXPECT_EQ((result_x == points[i].x), true);
374 EXPECT_EQ((result_y == points[i].y), true);
375 }
376}
377
378TEST(secp256k1, GroupExponentiationZeroAndOne)
379{
381
382 EXPECT_EQ(result.is_point_at_infinity(), true);
383
385
386 EXPECT_EQ(result == secp256k1::g1::affine_one, true);
387}
388
389TEST(secp256k1, GroupExponentiationConsistencyCheck)
390{
393
395 c = a * b;
396
398 secp256k1::g1::affine_element result = input * a;
399 result = result * b;
400
401 secp256k1::g1::affine_element expected = input * c;
402
403 EXPECT_EQ(result == expected, true);
404}
405
406TEST(secp256k1, DeriveGenerators)
407{
408 constexpr size_t num_generators = 128;
409 auto result = secp256k1::g1::derive_generators("test generators", num_generators);
410
411 const auto is_unique = [&result](const secp256k1::g1::affine_element& y, const size_t j) {
412 for (size_t i = 0; i < result.size(); ++i) {
413 if ((i != j) && result[i] == y) {
414 return false;
415 }
416 }
417 return true;
418 };
419
420 for (size_t k = 0; k < num_generators; ++k) {
421 EXPECT_EQ(is_unique(result[k], k), true);
422 EXPECT_EQ(result[k].on_curve(), true);
423 }
424}
425
426TEST(secp256k1, GetEndomorphismScalars)
427{
428 for (size_t i = 0; i < 2048; i++) {
430 secp256k1::fr k1 = 0;
431 secp256k1::fr k2 = 0;
432
434 bool k1_neg = false;
435 bool k2_neg = false;
436
438 k2 = -k2;
439 k2_neg = true;
440 }
441
442 EXPECT_LT(k1.uint256_t_no_montgomery_conversion().get_msb(), 129ULL);
443 EXPECT_LT(k2.uint256_t_no_montgomery_conversion().get_msb(), 129ULL);
444
445 if (k1_neg) {
446 k1 = -k1;
447 }
448 if (k2_neg) {
449 k2 = -k2;
450 }
451
454
456 secp256k1::fr expected = k1 - k2 * beta;
457
458 expected.self_from_montgomery_form();
459 EXPECT_EQ(k, expected);
460 if (k != expected) {
461 break;
462 }
463 }
464}
465
466TEST(secp256k1, TestEndomorphismScalars)
467{
469 secp256k1::fr k1 = 0;
470 secp256k1::fr k2 = 0;
471
473 bool k1_neg = false;
474 bool k2_neg = false;
475
477 k1 = -k1;
478 k1_neg = true;
479 }
481 k2 = -k2;
482 k2_neg = true;
483 }
484
485 EXPECT_LT(k1.uint256_t_no_montgomery_conversion().get_msb(), 129ULL);
486 EXPECT_LT(k2.uint256_t_no_montgomery_conversion().get_msb(), 129ULL);
487
488 if (k1_neg) {
489 k1 = -k1;
490 }
491 if (k2_neg) {
492 k2 = -k2;
493 }
496 static const uint256_t secp256k1_const_lambda{
497 0xDF02967C1B23BD72ULL, 0x122E22EA20816678UL, 0xA5261C028812645AULL, 0x5363AD4CC05C30E0ULL
498 };
499
500 secp256k1::fr expected = k1 - k2 * secp256k1_const_lambda;
501
502 expected.self_from_montgomery_form();
503 EXPECT_EQ(k, expected);
504}
505
506TEST(secp256k1, NegAndSelfNeg0CmpRegression)
507{
508 secp256k1::fq a = 0;
509 secp256k1::fq a_neg = -a;
510 EXPECT_EQ((a == a_neg), true);
511 a = 0;
512 a_neg = 0;
513 a_neg.self_neg();
514 EXPECT_EQ((a == a_neg), true);
515}
516
517TEST(secp256k1, MontgomeryMulBigBug)
518{
519 secp256k1::fq a(uint256_t{ 0xfffffffe630dc02f, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff });
520 secp256k1::fq a_sqr = a.sqr();
521 secp256k1::fq expected(uint256_t{ 0x60381e557e100000, 0x0, 0x0, 0x0 });
522 EXPECT_EQ((a_sqr == expected), true);
523}
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
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.
TEST(MegaCircuitBuilder, CopyConstructor)
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