Skip to content

Commit cfabb11

Browse files
committed
Add native num.h implementation with 32- and 64-bit variants
This num.h implementation works using fixed-size arrays large enough to hold a 256-bit number (plus one word for slop). It includes a modular inversion. Typical perf numbers on my 64-bit system are: scalar_inverse: constant time: min 13.4us / avg 13.5us / max 13.8us native num.h: min 5.18us / avg 4.55us / max 5.43us gmp num.h: min 2.65us / avg 2.68us / max 2.70us field_inverse: constant time: min 6.02us / avg 6.09us / max 6.15us native num.h: min 5.48us / avg 4.94us / max 5.68us gmp num.h: min 2.96us / avg 3.02us / max 3.09us
1 parent caa3a1d commit cfabb11

14 files changed

+805
-36
lines changed

.travis.yml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,10 @@ env:
2020
- FIELD=64bit ENDOMORPHISM=yes ASM=x86_64
2121
- FIELD=32bit SCHNORR=yes
2222
- FIELD=32bit ENDOMORPHISM=yes
23-
- BIGNUM=no
24-
- BIGNUM=no ENDOMORPHISM=yes SCHNORR=yes RECOVERY=yes
25-
- BIGNUM=no STATICPRECOMPUTATION=no
23+
- BIGNUM=64bit
24+
- BIGNUM=64bit ENDOMORPHISM=yes SCHNORR=yes RECOVERY=yes
25+
- BIGNUM=32bit ENDOMORPHISM=yes SCHNORR=yes RECOVERY=yes
26+
- BIGNUM=32bit STATICPRECOMPUTATION=no
2627
- BUILD=distcheck
2728
- EXTRAFLAGS=CFLAGS=-DDETERMINISTIC
2829
matrix:

Makefile.am

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ noinst_HEADERS += src/group.h
1313
noinst_HEADERS += src/group_impl.h
1414
noinst_HEADERS += src/num_gmp.h
1515
noinst_HEADERS += src/num_gmp_impl.h
16+
noinst_HEADERS += src/num_5x64.h
17+
noinst_HEADERS += src/num_5x64_impl.h
18+
noinst_HEADERS += src/num_9x32.h
19+
noinst_HEADERS += src/num_9x32_impl.h
20+
noinst_HEADERS += src/num_native_impl.h
1621
noinst_HEADERS += src/ecdsa.h
1722
noinst_HEADERS += src/ecdsa_impl.h
1823
noinst_HEADERS += src/eckey.h

configure.ac

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ AC_ARG_ENABLE(module_recovery,
113113
AC_ARG_WITH([field], [AS_HELP_STRING([--with-field=64bit|32bit|auto],
114114
[Specify Field Implementation. Default is auto])],[req_field=$withval], [req_field=auto])
115115

116-
AC_ARG_WITH([bignum], [AS_HELP_STRING([--with-bignum=gmp|no|auto],
116+
AC_ARG_WITH([bignum], [AS_HELP_STRING([--with-bignum=gmp|64bit|32bit|auto],
117117
[Specify Bignum Implementation. Default is auto])],[req_bignum=$withval], [req_bignum=auto])
118118

119119
AC_ARG_WITH([scalar], [AS_HELP_STRING([--with-scalar=64bit|32bit|auto],
@@ -217,9 +217,14 @@ if test x"$req_bignum" = x"auto"; then
217217
if test x"$has_gmp" = x"yes"; then
218218
set_bignum=gmp
219219
fi
220-
220+
if test x"$set_field" = x; then
221+
SECP_INT128_CHECK
222+
if test x"$has_int128" = x"yes"; then
223+
set_bignum=64bit
224+
fi
225+
fi
221226
if test x"$set_bignum" = x; then
222-
set_bignum=no
227+
set_bignum=32bit
223228
fi
224229
else
225230
set_bignum=$req_bignum
@@ -230,7 +235,12 @@ else
230235
AC_MSG_ERROR([gmp bignum explicitly requested but libgmp not available])
231236
fi
232237
;;
233-
no)
238+
32bit)
239+
;;
240+
64bit)
241+
if test x"$has_int128" != x"yes"; then
242+
AC_MSG_ERROR([64bit bignum explicitly requested but __int128 support is not available])
243+
fi
234244
;;
235245
*)
236246
AC_MSG_ERROR([invalid bignum implementation selection])
@@ -271,10 +281,15 @@ gmp)
271281
AC_DEFINE(USE_FIELD_INV_NUM, 1, [Define this symbol to use the num-based field inverse implementation])
272282
AC_DEFINE(USE_SCALAR_INV_NUM, 1, [Define this symbol to use the num-based scalar inverse implementation])
273283
;;
274-
no)
275-
AC_DEFINE(USE_NUM_NONE, 1, [Define this symbol to use no num implementation])
276-
AC_DEFINE(USE_FIELD_INV_BUILTIN, 1, [Define this symbol to use the native field inverse implementation])
277-
AC_DEFINE(USE_SCALAR_INV_BUILTIN, 1, [Define this symbol to use the native scalar inverse implementation])
284+
32bit)
285+
AC_DEFINE(USE_NUM_9X32, 1, [Define this symbol to use the native 32-bit num implementation])
286+
AC_DEFINE(USE_FIELD_INV_NUM, 1, [Define this symbol to use the num-based field inverse implementation])
287+
AC_DEFINE(USE_SCALAR_INV_NUM, 1, [Define this symbol to use the num-based scalar inverse implementation])
288+
;;
289+
64bit)
290+
AC_DEFINE(USE_NUM_5X64, 1, [Define this symbol to use the native 64-bit num implementation])
291+
AC_DEFINE(USE_FIELD_INV_NUM, 1, [Define this symbol to use the num-based field inverse implementation])
292+
AC_DEFINE(USE_SCALAR_INV_NUM, 1, [Define this symbol to use the num-based scalar inverse implementation])
278293
;;
279294
*)
280295
AC_MSG_ERROR([invalid bignum implementation])

src/basic-config.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,14 @@
1616
#undef USE_FIELD_INV_BUILTIN
1717
#undef USE_FIELD_INV_NUM
1818
#undef USE_NUM_GMP
19-
#undef USE_NUM_NONE
19+
#undef USE_NUM_5X64
20+
#undef USE_NUM_9X32
2021
#undef USE_SCALAR_4X64
2122
#undef USE_SCALAR_8X32
2223
#undef USE_SCALAR_INV_BUILTIN
2324
#undef USE_SCALAR_INV_NUM
2425

25-
#define USE_NUM_NONE 1
26+
#define USE_NUM_9X32 1
2627
#define USE_FIELD_INV_BUILTIN 1
2728
#define USE_SCALAR_INV_BUILTIN 1
2829
#define USE_FIELD_10X26 1

src/field_10x26_impl.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
#include <stdio.h>
1111
#include <string.h>
1212
#include "util.h"
13-
#include "num.h"
13+
#include "num_impl.h"
1414
#include "field.h"
1515

1616
#ifdef VERIFY

src/field_impl.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@
2121
#error "Please select field implementation"
2222
#endif
2323

24+
#if defined(USE_FIELD_INV_NUM)
25+
#include "num_impl.h"
26+
#endif
27+
2428
SECP256K1_INLINE static int secp256k1_fe_equal_var(const secp256k1_fe_t *a, const secp256k1_fe_t *b) {
2529
secp256k1_fe_t na;
2630
secp256k1_fe_negate(&na, a, 1);

src/num.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,16 @@
77
#ifndef _SECP256K1_NUM_
88
#define _SECP256K1_NUM_
99

10-
#ifndef USE_NUM_NONE
11-
1210
#if defined HAVE_CONFIG_H
1311
#include "libsecp256k1-config.h"
1412
#endif
1513

1614
#if defined(USE_NUM_GMP)
1715
#include "num_gmp.h"
16+
#elif defined(USE_NUM_5X64)
17+
#include "num_5x64.h"
18+
#elif defined(USE_NUM_9X32)
19+
#include "num_9x32.h"
1820
#else
1921
#error "Please select num implementation"
2022
#endif
@@ -61,5 +63,3 @@ static int secp256k1_num_is_neg(const secp256k1_num_t *a);
6163
static void secp256k1_num_negate(secp256k1_num_t *r);
6264

6365
#endif
64-
65-
#endif

src/num_5x64.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
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_NUM_5X64_
8+
#define _SECP256K1_NUM_5X64_
9+
10+
#include "util.h"
11+
12+
#define NUM_N_WORDS 5
13+
#define NUM_WORD_WIDTH 64
14+
#define NUM_WORD_CTLZ __builtin_clzl
15+
typedef uint64_t secp256k1_num_word_t;
16+
typedef int64_t secp256k1_num_sword_t;
17+
typedef uint128_t secp256k1_num_dword_t;
18+
19+
typedef struct {
20+
/* we need an extra word for auxiallary stuff during algorithms,
21+
* so we have an extra word beyond what we need for 256-bit
22+
* numbers. Import/export (by set_bin and get_bin) expects to
23+
* work with 32-byte buffers, so the top word is not directly
24+
* accessible to users of the API. */
25+
secp256k1_num_word_t data[NUM_N_WORDS];
26+
} secp256k1_num_t;
27+
28+
#endif

src/num_5x64_impl.h

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
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_NUM_5X64_IMPL_
8+
#define _SECP256K1_NUM_5X64_IMPL_
9+
10+
#include <string.h>
11+
12+
#include "num.h"
13+
#include "num_5x64.h"
14+
#include "util.h"
15+
16+
#include "num_native_impl.h"
17+
18+
static void secp256k1_num_debug_print(const char *name, const secp256k1_num_t *a) {
19+
int i;
20+
printf ("%s: 0x", name);
21+
for (i = 4; i >= 0; --i)
22+
printf("%016lx", a->data[i]);
23+
puts("");
24+
}
25+
26+
static void secp256k1_num_get_bin(unsigned char *r, unsigned int rlen, const secp256k1_num_t *a) {
27+
uint64_t v;
28+
(void) rlen;
29+
VERIFY_CHECK(rlen >= 32);
30+
31+
v = BE64(a->data[3]); memcpy(&r[0], &v, sizeof(v));
32+
v = BE64(a->data[2]); memcpy(&r[8], &v, sizeof(v));
33+
v = BE64(a->data[1]); memcpy(&r[16], &v, sizeof(v));
34+
v = BE64(a->data[0]); memcpy(&r[24], &v, sizeof(v));
35+
}
36+
37+
static void secp256k1_num_set_bin(secp256k1_num_t *r, const unsigned char *a, unsigned int alen) {
38+
uint64_t v;
39+
(void) alen;
40+
VERIFY_CHECK(alen >= 32);
41+
42+
r->data[4] = 0;
43+
memcpy(&v, &a[0], sizeof(v)); r->data[3] = BE64(v);
44+
memcpy(&v, &a[8], sizeof(v)); r->data[2] = BE64(v);
45+
memcpy(&v, &a[16], sizeof(v)); r->data[1] = BE64(v);
46+
memcpy(&v, &a[24], sizeof(v)); r->data[0] = BE64(v);
47+
}
48+
49+
#endif

src/num_9x32.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
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_NUM_9X32_
8+
#define _SECP256K1_NUM_9X32_
9+
10+
#include "util.h"
11+
12+
#define NUM_N_WORDS 9
13+
#define NUM_WORD_WIDTH 32
14+
#define NUM_WORD_CTLZ __builtin_clz
15+
typedef uint32_t secp256k1_num_word_t;
16+
typedef int32_t secp256k1_num_sword_t;
17+
typedef uint64_t secp256k1_num_dword_t;
18+
19+
typedef struct {
20+
/* we need an extra word for auxiallary stuff during algorithms,
21+
* so we have an extra word beyond what we need for 256-bit
22+
* numbers. Import/export (by set_bin and get_bin) expects to
23+
* work with 32-byte buffers, so the top word is not directly
24+
* accessible to users of the API. */
25+
secp256k1_num_word_t data[NUM_N_WORDS];
26+
} secp256k1_num_t;
27+
28+
#endif

0 commit comments

Comments
 (0)