Skip to content

Commit 5726a17

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 6d46e4e commit 5726a17

14 files changed

+803
-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
25-
- BIGNUM=no STATICPRECOMPUTATION=no
23+
- BIGNUM=64bit
24+
- BIGNUM=64bit ENDOMORPHISM=yes SCHNORR=yes
25+
- BIGNUM=32bit ENDOMORPHISM=yes SCHNORR=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
@@ -117,7 +117,7 @@ AC_ARG_ENABLE(module_schnorr,
117117
AC_ARG_WITH([field], [AS_HELP_STRING([--with-field=64bit|32bit|auto],
118118
[Specify Field Implementation. Default is auto])],[req_field=$withval], [req_field=auto])
119119

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

123123
AC_ARG_WITH([scalar], [AS_HELP_STRING([--with-scalar=64bit|32bit|auto],
@@ -221,9 +221,14 @@ if test x"$req_bignum" = x"auto"; then
221221
if test x"$has_gmp" = x"yes"; then
222222
set_bignum=gmp
223223
fi
224-
224+
if test x"$set_field" = x; then
225+
SECP_INT128_CHECK
226+
if test x"$has_int128" = x"yes"; then
227+
set_bignum=64bit
228+
fi
229+
fi
225230
if test x"$set_bignum" = x; then
226-
set_bignum=no
231+
set_bignum=32bit
227232
fi
228233
else
229234
set_bignum=$req_bignum
@@ -234,7 +239,12 @@ else
234239
AC_MSG_ERROR([gmp bignum explicitly requested but libgmp not available])
235240
fi
236241
;;
237-
no)
242+
32bit)
243+
;;
244+
64bit)
245+
if test x"$has_int128" != x"yes"; then
246+
AC_MSG_ERROR([64bit bignum explicitly requested but __int128 support is not available])
247+
fi
238248
;;
239249
*)
240250
AC_MSG_ERROR([invalid bignum implementation selection])
@@ -275,10 +285,15 @@ gmp)
275285
AC_DEFINE(USE_FIELD_INV_NUM, 1, [Define this symbol to use the num-based field inverse implementation])
276286
AC_DEFINE(USE_SCALAR_INV_NUM, 1, [Define this symbol to use the num-based scalar inverse implementation])
277287
;;
278-
no)
279-
AC_DEFINE(USE_NUM_NONE, 1, [Define this symbol to use no num implementation])
280-
AC_DEFINE(USE_FIELD_INV_BUILTIN, 1, [Define this symbol to use the native field inverse implementation])
281-
AC_DEFINE(USE_SCALAR_INV_BUILTIN, 1, [Define this symbol to use the native scalar inverse implementation])
288+
32bit)
289+
AC_DEFINE(USE_NUM_9X32, 1, [Define this symbol to use the native 32-bit num implementation])
290+
AC_DEFINE(USE_FIELD_INV_NUM, 1, [Define this symbol to use the num-based field inverse implementation])
291+
AC_DEFINE(USE_SCALAR_INV_NUM, 1, [Define this symbol to use the num-based scalar inverse implementation])
292+
;;
293+
64bit)
294+
AC_DEFINE(USE_NUM_5X64, 1, [Define this symbol to use the native 64-bit num implementation])
295+
AC_DEFINE(USE_FIELD_INV_NUM, 1, [Define this symbol to use the num-based field inverse implementation])
296+
AC_DEFINE(USE_SCALAR_INV_NUM, 1, [Define this symbol to use the num-based scalar inverse implementation])
282297
;;
283298
*)
284299
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

src/num_9x32_impl.h

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
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_IMPL_
8+
#define _SECP256K1_NUM_9X32_IMPL_
9+
10+
#include <string.h>
11+
12+
#include "num.h"
13+
#include "num_9x32.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 = 8; i >= 0; --i)
22+
printf("%08x", 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+
uint32_t v;
28+
(void) rlen;
29+
VERIFY_CHECK(rlen >= 32);
30+
31+
v = BE32(a->data[7]); memcpy(&r[0], &v, sizeof(v));
32+
v = BE32(a->data[6]); memcpy(&r[4], &v, sizeof(v));
33+
v = BE32(a->data[5]); memcpy(&r[8], &v, sizeof(v));
34+
v = BE32(a->data[4]); memcpy(&r[12], &v, sizeof(v));
35+
v = BE32(a->data[3]); memcpy(&r[16], &v, sizeof(v));
36+
v = BE32(a->data[2]); memcpy(&r[20], &v, sizeof(v));
37+
v = BE32(a->data[1]); memcpy(&r[24], &v, sizeof(v));
38+
v = BE32(a->data[0]); memcpy(&r[28], &v, sizeof(v));
39+
}
40+
41+
static void secp256k1_num_set_bin(secp256k1_num_t *r, const unsigned char *a, unsigned int alen) {
42+
uint32_t v;
43+
(void) alen;
44+
VERIFY_CHECK(alen >= 32);
45+
46+
r->data[8] = 0;
47+
memcpy(&v, &a[0], sizeof(v)); r->data[7] = BE32(v);
48+
memcpy(&v, &a[4], sizeof(v)); r->data[6] = BE32(v);
49+
memcpy(&v, &a[8], sizeof(v)); r->data[5] = BE32(v);
50+
memcpy(&v, &a[12], sizeof(v)); r->data[4] = BE32(v);
51+
memcpy(&v, &a[16], sizeof(v)); r->data[3] = BE32(v);
52+
memcpy(&v, &a[20], sizeof(v)); r->data[2] = BE32(v);
53+
memcpy(&v, &a[24], sizeof(v)); r->data[1] = BE32(v);
54+
memcpy(&v, &a[28], sizeof(v)); r->data[0] = BE32(v);
55+
}
56+
57+
#endif

src/num_impl.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,10 @@
1515

1616
#if defined(USE_NUM_GMP)
1717
#include "num_gmp_impl.h"
18-
#elif defined(USE_NUM_NONE)
19-
/* Nothing. */
18+
#elif defined(USE_NUM_5X64)
19+
#include "num_5x64_impl.h"
20+
#elif defined(USE_NUM_9X32)
21+
#include "num_9x32_impl.h"
2022
#else
2123
#error "Please select num implementation"
2224
#endif

0 commit comments

Comments
 (0)