Skip to content

Commit 83836a9

Browse files
committed
Add exhaustive tests for group arithmetic, signing, and ecmult on a small group
If you compile without ./configure --enable-exhaustive-tests=no, this will create a binary ./exhaustive_tests which will execute every function possible on a group of small order obtained by moving to a twist of our curve and locating a generator of small order. Currently defaults to order 13, though by changing some #ifdefs you can get a couple other ones. (Currently 199, which will take forever to run, and 14, which won't work because it's composite.) TODO exhaustive tests for the various modules
1 parent 20b8877 commit 83836a9

9 files changed

+360
-30
lines changed

Makefile.am

+2-1
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@ noinst_HEADERS =
1212
noinst_HEADERS += src/scalar.h
1313
noinst_HEADERS += src/scalar_4x64.h
1414
noinst_HEADERS += src/scalar_8x32.h
15+
noinst_HEADERS += src/scalar_low.h
1516
noinst_HEADERS += src/scalar_impl.h
1617
noinst_HEADERS += src/scalar_4x64_impl.h
1718
noinst_HEADERS += src/scalar_8x32_impl.h
19+
noinst_HEADERS += src/scalar_low_impl.h
1820
noinst_HEADERS += src/group.h
1921
noinst_HEADERS += src/group_impl.h
2022
noinst_HEADERS += src/num_gmp.h
@@ -150,7 +152,6 @@ $(gen_context_BIN): $(gen_context_OBJECTS)
150152

151153
$(libsecp256k1_la_OBJECTS): src/ecmult_static_context.h
152154
$(tests_OBJECTS): src/ecmult_static_context.h
153-
$(exhaustive_tests_OBJECTS): src/ecmult_static_context.h
154155
$(bench_internal_OBJECTS): src/ecmult_static_context.h
155156

156157
src/ecmult_static_context.h: $(gen_context_BIN)

src/ecmult_const_impl.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ static int secp256k1_wnaf_const(int *wnaf, secp256k1_scalar s, int w) {
7878
/* Negative numbers will be negated to keep their bit representation below the maximum width */
7979
flip = secp256k1_scalar_is_high(&s);
8080
/* We add 1 to even numbers, 2 to odd ones, noting that negation flips parity */
81-
bit = flip ^ (s.d[0] & 1);
81+
bit = flip ^ !secp256k1_scalar_is_even(&s);
8282
/* We check for negative one, since adding 2 to it will cause an overflow */
8383
secp256k1_scalar_negate(&neg_s, &s);
8484
not_neg_one = !secp256k1_scalar_is_one(&neg_s);

src/ecmult_impl.h

+8-5
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,23 @@
1313
#include "scalar.h"
1414
#include "ecmult.h"
1515

16-
#include <string.h>
17-
18-
/* optimal for 128-bit and 256-bit exponents. */
19-
#define WINDOW_A 5
20-
2116
#if defined(EXHAUSTIVE_TEST_ORDER)
17+
/* We need to lower these values for exhaustive tests because
18+
* the tables cannot have infinities in them (this breaks the
19+
* affine-isomorphism stuff which tracks z-ratios) */
2220
# if EXHAUSTIVE_TEST_ORDER > 128
21+
# define WINDOW_A 5
2322
# define WINDOW_G 8
2423
# elif EXHAUSTIVE_TEST_ORDER > 8
24+
# define WINDOW_A 4
2525
# define WINDOW_G 4
2626
# else
27+
# define WINDOW_A 2
2728
# define WINDOW_G 2
2829
# endif
2930
#else
31+
/* optimal for 128-bit and 256-bit exponents. */
32+
#define WINDOW_A 5
3033
/** larger numbers may result in slightly better performance, at the cost of
3134
exponentially larger precomputed tables. */
3235
#ifdef USE_ENDOMORPHISM

src/group_impl.h

+40-3
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,31 @@
1111
#include "field.h"
1212
#include "group.h"
1313

14+
/* These points can be generated in sage as follows:
15+
*
16+
* 0. Setup a worksheet with the following parameters.
17+
* b = 4 # whatever CURVE_B will be set to
18+
* F = FiniteField (0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F)
19+
* C = EllipticCurve ([F (0), F (b)])
20+
*
21+
* 1. Determine all the small orders available to you. (If there are
22+
* no satisfactory ones, go back and change b.)
23+
* print C.order().factor(limit=1000)
24+
*
25+
* 2. Choose an order as one of the prime factors listed in the above step.
26+
* (You can also multiply some to get a composite order, though the
27+
* tests will crash trying to invert scalars during signing.) We take a
28+
* random point and scale it to drop its order to the desired value.
29+
* There is some probability this won't work; just try again.
30+
* order = 199
31+
* P = C.random_point()
32+
* P = (int(P.order()) / int(order)) * P
33+
* assert(P.order() == order)
34+
*
35+
* 3. Print the values. You'll need to use a vim macro or something to
36+
* split the hex output into 4-byte chunks.
37+
* print "%x %x" % P.xy()
38+
*/
1439
#if defined(EXHAUSTIVE_TEST_ORDER)
1540
# if EXHAUSTIVE_TEST_ORDER == 199
1641
const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST(
@@ -19,6 +44,16 @@ const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST(
1944
0x78AC123A, 0x5ED8AEF3, 0x8732BC91, 0x1F3A2868,
2045
0x48DF246C, 0x808DAE72, 0xCFE52572, 0x7F0501ED
2146
);
47+
48+
const int CURVE_B = 4;
49+
# elif EXHAUSTIVE_TEST_ORDER == 13
50+
const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST(
51+
0xedc60018, 0xa51a786b, 0x2ea91f4d, 0x4c9416c0,
52+
0x9de54c3b, 0xa1316554, 0x6cf4345c, 0x7277ef15,
53+
0x54cb1b6b, 0xdc8c1273, 0x087844ea, 0x43f4603e,
54+
0x0eaf9a43, 0xf6effe55, 0x939f806d, 0x37adf8ac
55+
);
56+
const int CURVE_B = 2;
2257
# else
2358
# error No known generator for the specified exhaustive test group order.
2459
# endif
@@ -32,6 +67,8 @@ static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST(
3267
0x483ADA77UL, 0x26A3C465UL, 0x5DA4FBFCUL, 0x0E1108A8UL,
3368
0xFD17B448UL, 0xA6855419UL, 0x9C47D08FUL, 0xFB10D4B8UL
3469
);
70+
71+
const int CURVE_B = 7;
3572
#endif
3673

3774
static void secp256k1_ge_set_gej_zinv(secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zi) {
@@ -188,7 +225,7 @@ static int secp256k1_ge_set_xquad(secp256k1_ge *r, const secp256k1_fe *x) {
188225
secp256k1_fe_sqr(&x2, x);
189226
secp256k1_fe_mul(&x3, x, &x2);
190227
r->infinity = 0;
191-
secp256k1_fe_set_int(&c, 7);
228+
secp256k1_fe_set_int(&c, CURVE_B);
192229
secp256k1_fe_add(&c, &x3);
193230
return secp256k1_fe_sqrt(&r->y, &c);
194231
}
@@ -247,7 +284,7 @@ static int secp256k1_gej_is_valid_var(const secp256k1_gej *a) {
247284
secp256k1_fe_sqr(&x3, &a->x); secp256k1_fe_mul(&x3, &x3, &a->x);
248285
secp256k1_fe_sqr(&z2, &a->z);
249286
secp256k1_fe_sqr(&z6, &z2); secp256k1_fe_mul(&z6, &z6, &z2);
250-
secp256k1_fe_mul_int(&z6, 7);
287+
secp256k1_fe_mul_int(&z6, CURVE_B);
251288
secp256k1_fe_add(&x3, &z6);
252289
secp256k1_fe_normalize_weak(&x3);
253290
return secp256k1_fe_equal_var(&y2, &x3);
@@ -261,7 +298,7 @@ static int secp256k1_ge_is_valid_var(const secp256k1_ge *a) {
261298
/* y^2 = x^3 + 7 */
262299
secp256k1_fe_sqr(&y2, &a->y);
263300
secp256k1_fe_sqr(&x3, &a->x); secp256k1_fe_mul(&x3, &x3, &a->x);
264-
secp256k1_fe_set_int(&c, 7);
301+
secp256k1_fe_set_int(&c, CURVE_B);
265302
secp256k1_fe_add(&x3, &c);
266303
secp256k1_fe_normalize_weak(&x3);
267304
return secp256k1_fe_equal_var(&y2, &x3);

src/scalar.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@
1313
#include "libsecp256k1-config.h"
1414
#endif
1515

16-
#if defined(USE_SCALAR_4X64)
16+
#if defined(EXHAUSTIVE_TEST_ORDER)
17+
#include "scalar_low.h"
18+
#elif defined(USE_SCALAR_4X64)
1719
#include "scalar_4x64.h"
1820
#elif defined(USE_SCALAR_8X32)
1921
#include "scalar_8x32.h"

src/scalar_impl.h

+37-2
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@
1414
#include "libsecp256k1-config.h"
1515
#endif
1616

17-
#if defined(USE_SCALAR_4X64)
17+
#if defined(EXHAUSTIVE_TEST_ORDER)
18+
#include "scalar_low_impl.h"
19+
#elif defined(USE_SCALAR_4X64)
1820
#include "scalar_4x64_impl.h"
1921
#elif defined(USE_SCALAR_8X32)
2022
#include "scalar_8x32_impl.h"
@@ -31,17 +33,37 @@ static void secp256k1_scalar_get_num(secp256k1_num *r, const secp256k1_scalar *a
3133

3234
/** secp256k1 curve order, see secp256k1_ecdsa_const_order_as_fe in ecdsa_impl.h */
3335
static void secp256k1_scalar_order_get_num(secp256k1_num *r) {
36+
#if defined(EXHAUSTIVE_TEST_ORDER)
37+
static const unsigned char order[32] = {
38+
0,0,0,0,0,0,0,0,
39+
0,0,0,0,0,0,0,0,
40+
0,0,0,0,0,0,0,0,
41+
0,0,0,0,0,0,0,EXHAUSTIVE_TEST_ORDER
42+
};
43+
#else
3444
static const unsigned char order[32] = {
3545
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
3646
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,
3747
0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,
3848
0xBF,0xD2,0x5E,0x8C,0xD0,0x36,0x41,0x41
3949
};
50+
#endif
4051
secp256k1_num_set_bin(r, order, 32);
4152
}
4253
#endif
4354

4455
static void secp256k1_scalar_inverse(secp256k1_scalar *r, const secp256k1_scalar *x) {
56+
#if defined(EXHAUSTIVE_TEST_ORDER)
57+
int i;
58+
*r = 0;
59+
for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++)
60+
if ((i * *x) % EXHAUSTIVE_TEST_ORDER == 1)
61+
*r = i;
62+
/* If this VERIFY_CHECK triggers we were given a noninvertible scalar (and thus
63+
* have a composite group order; fix it in exhaustive_tests.c). */
64+
VERIFY_CHECK(*r != 0);
65+
}
66+
#else
4567
secp256k1_scalar *t;
4668
int i;
4769
/* First compute x ^ (2^N - 1) for some values of N. */
@@ -233,9 +255,9 @@ static void secp256k1_scalar_inverse(secp256k1_scalar *r, const secp256k1_scalar
233255
}
234256

235257
SECP256K1_INLINE static int secp256k1_scalar_is_even(const secp256k1_scalar *a) {
236-
/* d[0] is present and is the lowest word for all representations */
237258
return !(a->d[0] & 1);
238259
}
260+
#endif
239261

240262
static void secp256k1_scalar_inverse_var(secp256k1_scalar *r, const secp256k1_scalar *x) {
241263
#if defined(USE_SCALAR_INV_BUILTIN)
@@ -259,6 +281,18 @@ static void secp256k1_scalar_inverse_var(secp256k1_scalar *r, const secp256k1_sc
259281
}
260282

261283
#ifdef USE_ENDOMORPHISM
284+
#if defined(EXHAUSTIVE_TEST_ORDER)
285+
/**
286+
* Find k1 and k2 given k, such that k1 + k2 * lambda == k mod n; unlike in the
287+
* full case we don't bother making k1 and k2 be small, we just want them to be
288+
* nontrivial to get full test coverage for the exhaustive tests. We therefore
289+
* (arbitrarily) set k2 = k + 5 and k1 = k - k2 * lambda.
290+
*/
291+
static void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a) {
292+
*r2 = (*a + 5) % EXHAUSTIVE_TEST_ORDER;
293+
*r1 = (*a + (EXHAUSTIVE_TEST_ORDER - *r2) * EXHAUSTIVE_TEST_LAMBDA) % EXHAUSTIVE_TEST_ORDER;
294+
}
295+
#else
262296
/**
263297
* The Secp256k1 curve has an endomorphism, where lambda * (x, y) = (beta * x, y), where
264298
* lambda is {0x53,0x63,0xad,0x4c,0xc0,0x5c,0x30,0xe0,0xa5,0x26,0x1c,0x02,0x88,0x12,0x64,0x5a,
@@ -331,5 +365,6 @@ static void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar
331365
secp256k1_scalar_add(r1, r1, a);
332366
}
333367
#endif
368+
#endif
334369

335370
#endif

src/scalar_low.h

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/**********************************************************************
2+
* Copyright (c) 2015 Andrew Poelstra *
3+
* Distributed under the MIT software license, see the accompanying *
4+
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
5+
**********************************************************************/
6+
7+
#ifndef _SECP256K1_SCALAR_REPR_
8+
#define _SECP256K1_SCALAR_REPR_
9+
10+
#include <stdint.h>
11+
12+
/** A scalar modulo the group order of the secp256k1 curve. */
13+
typedef uint32_t secp256k1_scalar;
14+
15+
#endif

src/scalar_low_impl.h

+114
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
/**********************************************************************
2+
* Copyright (c) 2015 Andrew Poelstra *
3+
* Distributed under the MIT software license, see the accompanying *
4+
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
5+
**********************************************************************/
6+
7+
#ifndef _SECP256K1_SCALAR_REPR_IMPL_H_
8+
#define _SECP256K1_SCALAR_REPR_IMPL_H_
9+
10+
#include "scalar.h"
11+
12+
#include <string.h>
13+
14+
SECP256K1_INLINE static int secp256k1_scalar_is_even(const secp256k1_scalar *a) {
15+
return !(*a & 1);
16+
}
17+
18+
SECP256K1_INLINE static void secp256k1_scalar_clear(secp256k1_scalar *r) { *r = 0; }
19+
SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsigned int v) { *r = v; }
20+
21+
SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar *a, unsigned int offset, unsigned int count) {
22+
if (offset < 32)
23+
return ((*a >> offset) & ((((uint32_t)1) << count) - 1));
24+
else
25+
return 0;
26+
}
27+
28+
SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count) {
29+
return secp256k1_scalar_get_bits(a, offset, count);
30+
}
31+
32+
SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scalar *a) { return *a >= EXHAUSTIVE_TEST_ORDER; }
33+
34+
static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) {
35+
*r = (*a + *b) % EXHAUSTIVE_TEST_ORDER;
36+
return *r < *b;
37+
}
38+
39+
static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag) {
40+
if (flag && bit < 32)
41+
*r += (1 << bit);
42+
#ifdef VERIFY
43+
VERIFY_CHECK(secp256k1_scalar_check_overflow(r) == 0);
44+
#endif
45+
}
46+
47+
static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *b32, int *overflow) {
48+
const int base = 0x100 % EXHAUSTIVE_TEST_ORDER;
49+
int i;
50+
*r = 0;
51+
for (i = 0; i < 32; i++) {
52+
*r = ((*r * base) + b32[i]) % EXHAUSTIVE_TEST_ORDER;
53+
}
54+
/* just deny overflow, it basically always happens */
55+
if (overflow) *overflow = 0;
56+
}
57+
58+
static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar* a) {
59+
memset(bin, 0, 32);
60+
bin[28] = *a >> 24; bin[29] = *a >> 16; bin[30] = *a >> 8; bin[31] = *a;
61+
}
62+
63+
SECP256K1_INLINE static int secp256k1_scalar_is_zero(const secp256k1_scalar *a) {
64+
return *a == 0;
65+
}
66+
67+
static void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar *a) {
68+
if (*a == 0) {
69+
*r = 0;
70+
} else {
71+
*r = EXHAUSTIVE_TEST_ORDER - *a;
72+
}
73+
}
74+
75+
SECP256K1_INLINE static int secp256k1_scalar_is_one(const secp256k1_scalar *a) {
76+
return *a == 1;
77+
}
78+
79+
static int secp256k1_scalar_is_high(const secp256k1_scalar *a) {
80+
return *a > EXHAUSTIVE_TEST_ORDER / 2;
81+
}
82+
83+
static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) {
84+
if (flag) secp256k1_scalar_negate(r, r);
85+
return flag ? -1 : 1;
86+
}
87+
88+
static void secp256k1_scalar_mul(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) {
89+
*r = (*a * *b) % EXHAUSTIVE_TEST_ORDER;
90+
}
91+
92+
static int secp256k1_scalar_shr_int(secp256k1_scalar *r, int n) {
93+
int ret;
94+
VERIFY_CHECK(n > 0);
95+
VERIFY_CHECK(n < 16);
96+
ret = *r & ((1 << n) - 1);
97+
*r >>= n;
98+
return ret;
99+
}
100+
101+
static void secp256k1_scalar_sqr(secp256k1_scalar *r, const secp256k1_scalar *a) {
102+
*r = (*a * *a) % EXHAUSTIVE_TEST_ORDER;
103+
}
104+
105+
static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a) {
106+
*r1 = *a;
107+
*r2 = 0;
108+
}
109+
110+
SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar *a, const secp256k1_scalar *b) {
111+
return *a == *b;
112+
}
113+
114+
#endif

0 commit comments

Comments
 (0)