Skip to content

Commit a8abae7

Browse files
committed
Merge dashpay#310: Add exhaustive test for group functions on a low-order subgroup
b4ceedf Add exhaustive test for verification (Andrew Poelstra) 83836a9 Add exhaustive tests for group arithmetic, signing, and ecmult on a small group (Andrew Poelstra) 20b8877 Add exhaustive test for group functions on a low-order subgroup (Andrew Poelstra)
2 parents 80773a6 + b4ceedf commit a8abae7

13 files changed

+622
-14
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ bench_schnorr_verify
66
bench_recover
77
bench_internal
88
tests
9+
exhaustive_tests
910
gen_context
1011
*.exe
1112
*.so

Makefile.am

+13-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
@@ -87,13 +89,23 @@ bench_internal_LDADD = $(SECP_LIBS) $(COMMON_LIB)
8789
bench_internal_CPPFLAGS = -DSECP256K1_BUILD $(SECP_INCLUDES)
8890
endif
8991

92+
TESTS =
9093
if USE_TESTS
9194
noinst_PROGRAMS += tests
9295
tests_SOURCES = src/tests.c
9396
tests_CPPFLAGS = -DSECP256K1_BUILD -DVERIFY -I$(top_srcdir)/src -I$(top_srcdir)/include $(SECP_INCLUDES) $(SECP_TEST_INCLUDES)
9497
tests_LDADD = $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB)
9598
tests_LDFLAGS = -static
96-
TESTS = tests
99+
TESTS += tests
100+
endif
101+
102+
if USE_EXHAUSTIVE_TESTS
103+
noinst_PROGRAMS += exhaustive_tests
104+
exhaustive_tests_SOURCES = src/tests_exhaustive.c
105+
exhaustive_tests_CPPFLAGS = -DSECP256K1_BUILD -DVERIFY -I$(top_srcdir)/src $(SECP_INCLUDES)
106+
exhaustive_tests_LDADD = $(SECP_LIBS)
107+
exhaustive_tests_LDFLAGS = -static
108+
TESTS += exhaustive_tests
97109
endif
98110

99111
JAVAROOT=src/java

configure.ac

+6
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,11 @@ AC_ARG_ENABLE(experimental,
104104
[use_experimental=$enableval],
105105
[use_experimental=no])
106106

107+
AC_ARG_ENABLE(exhaustive_tests,
108+
AS_HELP_STRING([--enable-exhaustive-tests],[compile exhaustive tests (default is yes)]),
109+
[use_exhaustive_tests=$enableval],
110+
[use_exhaustive_tests=yes])
111+
107112
AC_ARG_ENABLE(endomorphism,
108113
AS_HELP_STRING([--enable-endomorphism],[enable endomorphism (default is no)]),
109114
[use_endomorphism=$enableval],
@@ -456,6 +461,7 @@ AC_SUBST(SECP_LIBS)
456461
AC_SUBST(SECP_TEST_LIBS)
457462
AC_SUBST(SECP_TEST_INCLUDES)
458463
AM_CONDITIONAL([USE_TESTS], [test x"$use_tests" != x"no"])
464+
AM_CONDITIONAL([USE_EXHAUSTIVE_TESTS], [test x"$use_exhaustive_tests" != x"no"])
459465
AM_CONDITIONAL([USE_BENCHMARK], [test x"$use_benchmark" = x"yes"])
460466
AM_CONDITIONAL([USE_ECMULT_STATIC_PRECOMPUTATION], [test x"$set_precomp" = x"yes"])
461467
AM_CONDITIONAL([ENABLE_MODULE_ECDH], [test x"$enable_module_ecdh" = x"yes"])

src/ecdsa_impl.h

+18
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,9 @@ static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, size_t *size, const
203203
static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context *ctx, const secp256k1_scalar *sigr, const secp256k1_scalar *sigs, const secp256k1_ge *pubkey, const secp256k1_scalar *message) {
204204
unsigned char c[32];
205205
secp256k1_scalar sn, u1, u2;
206+
#if !defined(EXHAUSTIVE_TEST_ORDER)
206207
secp256k1_fe xr;
208+
#endif
207209
secp256k1_gej pubkeyj;
208210
secp256k1_gej pr;
209211

@@ -219,6 +221,21 @@ static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context *ctx, const
219221
if (secp256k1_gej_is_infinity(&pr)) {
220222
return 0;
221223
}
224+
225+
#if defined(EXHAUSTIVE_TEST_ORDER)
226+
{
227+
secp256k1_scalar computed_r;
228+
int overflow = 0;
229+
secp256k1_ge pr_ge;
230+
secp256k1_ge_set_gej(&pr_ge, &pr);
231+
secp256k1_fe_normalize(&pr_ge.x);
232+
233+
secp256k1_fe_get_b32(c, &pr_ge.x);
234+
secp256k1_scalar_set_b32(&computed_r, c, &overflow);
235+
/* we fully expect overflow */
236+
return secp256k1_scalar_eq(sigr, &computed_r);
237+
}
238+
#else
222239
secp256k1_scalar_get_b32(c, sigr);
223240
secp256k1_fe_set_b32(&xr, c);
224241

@@ -252,6 +269,7 @@ static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context *ctx, const
252269
return 1;
253270
}
254271
return 0;
272+
#endif
255273
}
256274

257275
static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context *ctx, secp256k1_scalar *sigr, secp256k1_scalar *sigs, const secp256k1_scalar *seckey, const secp256k1_scalar *message, const secp256k1_scalar *nonce, int *recid) {

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

+18-3
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,29 @@
77
#ifndef _SECP256K1_ECMULT_IMPL_H_
88
#define _SECP256K1_ECMULT_IMPL_H_
99

10+
#include <string.h>
11+
1012
#include "group.h"
1113
#include "scalar.h"
1214
#include "ecmult.h"
1315

14-
#include <string.h>
15-
16+
#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) */
20+
# if EXHAUSTIVE_TEST_ORDER > 128
21+
# define WINDOW_A 5
22+
# define WINDOW_G 8
23+
# elif EXHAUSTIVE_TEST_ORDER > 8
24+
# define WINDOW_A 4
25+
# define WINDOW_G 4
26+
# else
27+
# define WINDOW_A 2
28+
# define WINDOW_G 2
29+
# endif
30+
#else
1631
/* optimal for 128-bit and 256-bit exponents. */
1732
#define WINDOW_A 5
18-
1933
/** larger numbers may result in slightly better performance, at the cost of
2034
exponentially larger precomputed tables. */
2135
#ifdef USE_ENDOMORPHISM
@@ -25,6 +39,7 @@
2539
/** One table for window size 16: 1.375 MiB. */
2640
#define WINDOW_G 16
2741
#endif
42+
#endif
2843

2944
/** The number of entries a table with precomputed multiples needs to have. */
3045
#define ECMULT_TABLE_SIZE(w) (1 << ((w)-2))

src/field.h

+5
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
#error "Please select field implementation"
3131
#endif
3232

33+
#include "util.h"
34+
3335
/** Normalize a field element. */
3436
static void secp256k1_fe_normalize(secp256k1_fe *r);
3537

@@ -50,6 +52,9 @@ static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe *r);
5052
/** Set a field element equal to a small integer. Resulting field element is normalized. */
5153
static void secp256k1_fe_set_int(secp256k1_fe *r, int a);
5254

55+
/** Sets a field element equal to zero, initializing all fields. */
56+
static void secp256k1_fe_clear(secp256k1_fe *a);
57+
5358
/** Verify whether a field element is zero. Requires the input to be normalized. */
5459
static int secp256k1_fe_is_zero(const secp256k1_fe *a);
5560

src/group_impl.h

+62-6
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,53 @@
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+
*/
39+
#if defined(EXHAUSTIVE_TEST_ORDER)
40+
# if EXHAUSTIVE_TEST_ORDER == 199
41+
const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST(
42+
0xFA7CC9A7, 0x0737F2DB, 0xA749DD39, 0x2B4FB069,
43+
0x3B017A7D, 0xA808C2F1, 0xFB12940C, 0x9EA66C18,
44+
0x78AC123A, 0x5ED8AEF3, 0x8732BC91, 0x1F3A2868,
45+
0x48DF246C, 0x808DAE72, 0xCFE52572, 0x7F0501ED
46+
);
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;
57+
# else
58+
# error No known generator for the specified exhaustive test group order.
59+
# endif
60+
#else
1461
/** Generator for secp256k1, value 'g' defined in
1562
* "Standards for Efficient Cryptography" (SEC2) 2.7.1.
1663
*/
@@ -21,6 +68,9 @@ static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST(
2168
0xFD17B448UL, 0xA6855419UL, 0x9C47D08FUL, 0xFB10D4B8UL
2269
);
2370

71+
const int CURVE_B = 7;
72+
#endif
73+
2474
static void secp256k1_ge_set_gej_zinv(secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zi) {
2575
secp256k1_fe zi2;
2676
secp256k1_fe zi3;
@@ -145,9 +195,15 @@ static void secp256k1_ge_globalz_set_table_gej(size_t len, secp256k1_ge *r, secp
145195

146196
static void secp256k1_gej_set_infinity(secp256k1_gej *r) {
147197
r->infinity = 1;
148-
secp256k1_fe_set_int(&r->x, 0);
149-
secp256k1_fe_set_int(&r->y, 0);
150-
secp256k1_fe_set_int(&r->z, 0);
198+
secp256k1_fe_clear(&r->x);
199+
secp256k1_fe_clear(&r->y);
200+
secp256k1_fe_clear(&r->z);
201+
}
202+
203+
static void secp256k1_ge_set_infinity(secp256k1_ge *r) {
204+
r->infinity = 1;
205+
secp256k1_fe_clear(&r->x);
206+
secp256k1_fe_clear(&r->y);
151207
}
152208

153209
static void secp256k1_gej_clear(secp256k1_gej *r) {
@@ -169,7 +225,7 @@ static int secp256k1_ge_set_xquad(secp256k1_ge *r, const secp256k1_fe *x) {
169225
secp256k1_fe_sqr(&x2, x);
170226
secp256k1_fe_mul(&x3, x, &x2);
171227
r->infinity = 0;
172-
secp256k1_fe_set_int(&c, 7);
228+
secp256k1_fe_set_int(&c, CURVE_B);
173229
secp256k1_fe_add(&c, &x3);
174230
return secp256k1_fe_sqrt(&r->y, &c);
175231
}
@@ -228,7 +284,7 @@ static int secp256k1_gej_is_valid_var(const secp256k1_gej *a) {
228284
secp256k1_fe_sqr(&x3, &a->x); secp256k1_fe_mul(&x3, &x3, &a->x);
229285
secp256k1_fe_sqr(&z2, &a->z);
230286
secp256k1_fe_sqr(&z6, &z2); secp256k1_fe_mul(&z6, &z6, &z2);
231-
secp256k1_fe_mul_int(&z6, 7);
287+
secp256k1_fe_mul_int(&z6, CURVE_B);
232288
secp256k1_fe_add(&x3, &z6);
233289
secp256k1_fe_normalize_weak(&x3);
234290
return secp256k1_fe_equal_var(&y2, &x3);
@@ -242,7 +298,7 @@ static int secp256k1_ge_is_valid_var(const secp256k1_ge *a) {
242298
/* y^2 = x^3 + 7 */
243299
secp256k1_fe_sqr(&y2, &a->y);
244300
secp256k1_fe_sqr(&x3, &a->x); secp256k1_fe_mul(&x3, &x3, &a->x);
245-
secp256k1_fe_set_int(&c, 7);
301+
secp256k1_fe_set_int(&c, CURVE_B);
246302
secp256k1_fe_add(&x3, &c);
247303
secp256k1_fe_normalize_weak(&x3);
248304
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

0 commit comments

Comments
 (0)