Skip to content

Commit

Permalink
Add native num.h implementation with 32- and 64-bit variants
Browse files Browse the repository at this point in the history
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
  • Loading branch information
apoelstra committed Oct 26, 2015
1 parent 551870e commit f6577c1
Show file tree
Hide file tree
Showing 14 changed files with 805 additions and 36 deletions.
7 changes: 4 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,10 @@ env:
- FIELD=64bit ENDOMORPHISM=yes ASM=x86_64
- FIELD=32bit SCHNORR=yes
- FIELD=32bit ENDOMORPHISM=yes
- BIGNUM=no
- BIGNUM=no ENDOMORPHISM=yes SCHNORR=yes RECOVERY=yes
- BIGNUM=no STATICPRECOMPUTATION=no
- BIGNUM=64bit
- BIGNUM=64bit ENDOMORPHISM=yes SCHNORR=yes RECOVERY=yes
- BIGNUM=32bit ENDOMORPHISM=yes SCHNORR=yes RECOVERY=yes
- BIGNUM=32bit STATICPRECOMPUTATION=no
- BUILD=distcheck
- EXTRAFLAGS=CPPFLAGS=-DDETERMINISTIC
- EXTRAFLAGS=CFLAGS=-O0
Expand Down
5 changes: 5 additions & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ noinst_HEADERS += src/group.h
noinst_HEADERS += src/group_impl.h
noinst_HEADERS += src/num_gmp.h
noinst_HEADERS += src/num_gmp_impl.h
noinst_HEADERS += src/num_5x64.h
noinst_HEADERS += src/num_5x64_impl.h
noinst_HEADERS += src/num_9x32.h
noinst_HEADERS += src/num_9x32_impl.h
noinst_HEADERS += src/num_native_impl.h
noinst_HEADERS += src/ecdsa.h
noinst_HEADERS += src/ecdsa_impl.h
noinst_HEADERS += src/eckey.h
Expand Down
31 changes: 23 additions & 8 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ AC_ARG_ENABLE(module_recovery,
AC_ARG_WITH([field], [AS_HELP_STRING([--with-field=64bit|32bit|auto],
[Specify Field Implementation. Default is auto])],[req_field=$withval], [req_field=auto])

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

AC_ARG_WITH([scalar], [AS_HELP_STRING([--with-scalar=64bit|32bit|auto],
Expand Down Expand Up @@ -225,9 +225,14 @@ if test x"$req_bignum" = x"auto"; then
if test x"$has_gmp" = x"yes"; then
set_bignum=gmp
fi

if test x"$set_field" = x; then
SECP_INT128_CHECK
if test x"$has_int128" = x"yes"; then
set_bignum=64bit
fi
fi
if test x"$set_bignum" = x; then
set_bignum=no
set_bignum=32bit
fi
else
set_bignum=$req_bignum
Expand All @@ -238,7 +243,12 @@ else
AC_MSG_ERROR([gmp bignum explicitly requested but libgmp not available])
fi
;;
no)
32bit)
;;
64bit)
if test x"$has_int128" != x"yes"; then
AC_MSG_ERROR([64bit bignum explicitly requested but __int128 support is not available])
fi
;;
*)
AC_MSG_ERROR([invalid bignum implementation selection])
Expand Down Expand Up @@ -279,10 +289,15 @@ gmp)
AC_DEFINE(USE_FIELD_INV_NUM, 1, [Define this symbol to use the num-based field inverse implementation])
AC_DEFINE(USE_SCALAR_INV_NUM, 1, [Define this symbol to use the num-based scalar inverse implementation])
;;
no)
AC_DEFINE(USE_NUM_NONE, 1, [Define this symbol to use no num implementation])
AC_DEFINE(USE_FIELD_INV_BUILTIN, 1, [Define this symbol to use the native field inverse implementation])
AC_DEFINE(USE_SCALAR_INV_BUILTIN, 1, [Define this symbol to use the native scalar inverse implementation])
32bit)
AC_DEFINE(USE_NUM_9X32, 1, [Define this symbol to use the native 32-bit num implementation])
AC_DEFINE(USE_FIELD_INV_NUM, 1, [Define this symbol to use the num-based field inverse implementation])
AC_DEFINE(USE_SCALAR_INV_NUM, 1, [Define this symbol to use the num-based scalar inverse implementation])
;;
64bit)
AC_DEFINE(USE_NUM_5X64, 1, [Define this symbol to use the native 64-bit num implementation])
AC_DEFINE(USE_FIELD_INV_NUM, 1, [Define this symbol to use the num-based field inverse implementation])
AC_DEFINE(USE_SCALAR_INV_NUM, 1, [Define this symbol to use the num-based scalar inverse implementation])
;;
*)
AC_MSG_ERROR([invalid bignum implementation])
Expand Down
5 changes: 3 additions & 2 deletions src/basic-config.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,14 @@
#undef USE_FIELD_INV_BUILTIN
#undef USE_FIELD_INV_NUM
#undef USE_NUM_GMP
#undef USE_NUM_NONE
#undef USE_NUM_5X64
#undef USE_NUM_9X32
#undef USE_SCALAR_4X64
#undef USE_SCALAR_8X32
#undef USE_SCALAR_INV_BUILTIN
#undef USE_SCALAR_INV_NUM

#define USE_NUM_NONE 1
#define USE_NUM_9X32 1
#define USE_FIELD_INV_BUILTIN 1
#define USE_SCALAR_INV_BUILTIN 1
#define USE_FIELD_10X26 1
Expand Down
2 changes: 1 addition & 1 deletion src/field_10x26_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#include <stdio.h>
#include <string.h>
#include "util.h"
#include "num.h"
#include "num_impl.h"
#include "field.h"

#ifdef VERIFY
Expand Down
4 changes: 4 additions & 0 deletions src/field_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@
#error "Please select field implementation"
#endif

#if defined(USE_FIELD_INV_NUM)
#include "num_impl.h"
#endif

SECP256K1_INLINE static int secp256k1_fe_equal_var(const secp256k1_fe *a, const secp256k1_fe *b) {
secp256k1_fe na;
secp256k1_fe_negate(&na, a, 1);
Expand Down
8 changes: 4 additions & 4 deletions src/num.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,16 @@
#ifndef _SECP256K1_NUM_
#define _SECP256K1_NUM_

#ifndef USE_NUM_NONE

#if defined HAVE_CONFIG_H
#include "libsecp256k1-config.h"
#endif

#if defined(USE_NUM_GMP)
#include "num_gmp.h"
#elif defined(USE_NUM_5X64)
#include "num_5x64.h"
#elif defined(USE_NUM_9X32)
#include "num_9x32.h"
#else
#error "Please select num implementation"
#endif
Expand Down Expand Up @@ -61,5 +63,3 @@ static int secp256k1_num_is_neg(const secp256k1_num *a);
static void secp256k1_num_negate(secp256k1_num *r);

#endif

#endif
28 changes: 28 additions & 0 deletions src/num_5x64.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**********************************************************************
* Copyright (c) 2015 Andrew Poelstra *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/

#ifndef _SECP256K1_NUM_5X64_
#define _SECP256K1_NUM_5X64_

#include "util.h"

#define NUM_N_WORDS 5
#define NUM_WORD_WIDTH 64
#define NUM_WORD_CTLZ __builtin_clzl
typedef uint64_t secp256k1_num_word;
typedef int64_t secp256k1_num_sword;
typedef uint128_t secp256k1_num_dword;

typedef struct {
/* we need an extra word for auxiallary stuff during algorithms,
* so we have an extra word beyond what we need for 256-bit
* numbers. Import/export (by set_bin and get_bin) expects to
* work with 32-byte buffers, so the top word is not directly
* accessible to users of the API. */
secp256k1_num_word data[NUM_N_WORDS];
} secp256k1_num;

#endif
49 changes: 49 additions & 0 deletions src/num_5x64_impl.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/**********************************************************************
* Copyright (c) 2015 Andrew Poelstra *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/

#ifndef _SECP256K1_NUM_5X64_IMPL_
#define _SECP256K1_NUM_5X64_IMPL_

#include <string.h>

#include "num.h"
#include "num_5x64.h"
#include "util.h"

#include "num_native_impl.h"

static void secp256k1_num_debug_print(const char *name, const secp256k1_num *a) {
int i;
printf ("%s: 0x", name);
for (i = 4; i >= 0; --i)
printf("%016lx", a->data[i]);
puts("");
}

static void secp256k1_num_get_bin(unsigned char *r, unsigned int rlen, const secp256k1_num *a) {
uint64_t v;
(void) rlen;
VERIFY_CHECK(rlen >= 32);

v = BE64(a->data[3]); memcpy(&r[0], &v, sizeof(v));
v = BE64(a->data[2]); memcpy(&r[8], &v, sizeof(v));
v = BE64(a->data[1]); memcpy(&r[16], &v, sizeof(v));
v = BE64(a->data[0]); memcpy(&r[24], &v, sizeof(v));
}

static void secp256k1_num_set_bin(secp256k1_num *r, const unsigned char *a, unsigned int alen) {
uint64_t v;
(void) alen;
VERIFY_CHECK(alen >= 32);

r->data[4] = 0;
memcpy(&v, &a[0], sizeof(v)); r->data[3] = BE64(v);
memcpy(&v, &a[8], sizeof(v)); r->data[2] = BE64(v);
memcpy(&v, &a[16], sizeof(v)); r->data[1] = BE64(v);
memcpy(&v, &a[24], sizeof(v)); r->data[0] = BE64(v);
}

#endif
28 changes: 28 additions & 0 deletions src/num_9x32.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**********************************************************************
* Copyright (c) 2015 Andrew Poelstra *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/

#ifndef _SECP256K1_NUM_9X32_
#define _SECP256K1_NUM_9X32_

#include "util.h"

#define NUM_N_WORDS 9
#define NUM_WORD_WIDTH 32
#define NUM_WORD_CTLZ __builtin_clz
typedef uint32_t secp256k1_num_word;
typedef int32_t secp256k1_num_sword;
typedef uint64_t secp256k1_num_dword;

typedef struct {
/* we need an extra word for auxiallary stuff during algorithms,
* so we have an extra word beyond what we need for 256-bit
* numbers. Import/export (by set_bin and get_bin) expects to
* work with 32-byte buffers, so the top word is not directly
* accessible to users of the API. */
secp256k1_num_word data[NUM_N_WORDS];
} secp256k1_num;

#endif
57 changes: 57 additions & 0 deletions src/num_9x32_impl.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/**********************************************************************
* Copyright (c) 2015 Andrew Poelstra *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/

#ifndef _SECP256K1_NUM_9X32_IMPL_
#define _SECP256K1_NUM_9X32_IMPL_

#include <string.h>

#include "num.h"
#include "num_9x32.h"
#include "util.h"

#include "num_native_impl.h"

static void secp256k1_num_debug_print(const char *name, const secp256k1_num *a) {
int i;
printf ("%s: 0x", name);
for (i = 8; i >= 0; --i)
printf("%08x", a->data[i]);
puts("");
}

static void secp256k1_num_get_bin(unsigned char *r, unsigned int rlen, const secp256k1_num *a) {
uint32_t v;
(void) rlen;
VERIFY_CHECK(rlen >= 32);

v = BE32(a->data[7]); memcpy(&r[0], &v, sizeof(v));
v = BE32(a->data[6]); memcpy(&r[4], &v, sizeof(v));
v = BE32(a->data[5]); memcpy(&r[8], &v, sizeof(v));
v = BE32(a->data[4]); memcpy(&r[12], &v, sizeof(v));
v = BE32(a->data[3]); memcpy(&r[16], &v, sizeof(v));
v = BE32(a->data[2]); memcpy(&r[20], &v, sizeof(v));
v = BE32(a->data[1]); memcpy(&r[24], &v, sizeof(v));
v = BE32(a->data[0]); memcpy(&r[28], &v, sizeof(v));
}

static void secp256k1_num_set_bin(secp256k1_num *r, const unsigned char *a, unsigned int alen) {
uint32_t v;
(void) alen;
VERIFY_CHECK(alen >= 32);

r->data[8] = 0;
memcpy(&v, &a[0], sizeof(v)); r->data[7] = BE32(v);
memcpy(&v, &a[4], sizeof(v)); r->data[6] = BE32(v);
memcpy(&v, &a[8], sizeof(v)); r->data[5] = BE32(v);
memcpy(&v, &a[12], sizeof(v)); r->data[4] = BE32(v);
memcpy(&v, &a[16], sizeof(v)); r->data[3] = BE32(v);
memcpy(&v, &a[20], sizeof(v)); r->data[2] = BE32(v);
memcpy(&v, &a[24], sizeof(v)); r->data[1] = BE32(v);
memcpy(&v, &a[28], sizeof(v)); r->data[0] = BE32(v);
}

#endif
6 changes: 4 additions & 2 deletions src/num_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@

#if defined(USE_NUM_GMP)
#include "num_gmp_impl.h"
#elif defined(USE_NUM_NONE)
/* Nothing. */
#elif defined(USE_NUM_5X64)
#include "num_5x64_impl.h"
#elif defined(USE_NUM_9X32)
#include "num_9x32_impl.h"
#else
#error "Please select num implementation"
#endif
Expand Down
Loading

0 comments on commit f6577c1

Please sign in to comment.