Skip to content

Add native num implementation; modular inverse and Jacobi symbol without GMP #290

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
14 changes: 14 additions & 0 deletions src/bench_internal.c
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,19 @@ void bench_context_sign(void* arg) {
}
}

void bench_num_jacobi(void* arg) {
int i;
bench_inv_t *data = (bench_inv_t*)arg;
secp256k1_num nx, norder;

secp256k1_scalar_get_num(&nx, &data->scalar_x);
secp256k1_scalar_order_get_num(&norder);
secp256k1_scalar_get_num(&norder, &data->scalar_y);

for (i = 0; i < 2000; i++) {
secp256k1_num_jacobi(&nx, &norder);
}
}

int have_flag(int argc, char** argv, char *flag) {
char** argm = argv + argc;
Expand Down Expand Up @@ -350,5 +363,6 @@ int main(int argc, char **argv) {
if (have_flag(argc, argv, "context") || have_flag(argc, argv, "verify")) run_benchmark("context_verify", bench_context_verify, bench_setup, NULL, &data, 10, 20);
if (have_flag(argc, argv, "context") || have_flag(argc, argv, "sign")) run_benchmark("context_sign", bench_context_sign, bench_setup, NULL, &data, 10, 200);

if (have_flag(argc, argv, "num") || have_flag(argc, argv, "jacobi")) run_benchmark("num_jacobi", bench_num_jacobi, bench_setup, NULL, &data, 10, 200000);
return 0;
}
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
7 changes: 1 addition & 6 deletions src/hash_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#define _SECP256K1_HASH_IMPL_H_

#include "hash.h"
#include "util.h"

#include <stdlib.h>
#include <stdint.h>
Expand All @@ -27,12 +28,6 @@
(h) = t1 + t2; \
} while(0)

#ifdef WORDS_BIGENDIAN
#define BE32(x) (x)
#else
#define BE32(p) ((((p) & 0xFF) << 24) | (((p) & 0xFF00) << 8) | (((p) & 0xFF0000) >> 8) | (((p) & 0xFF000000) >> 24))
#endif

static void secp256k1_sha256_initialize(secp256k1_sha256_t *hash) {
hash->s[0] = 0x6a09e667ul;
hash->s[1] = 0xbb67ae85ul;
Expand Down
17 changes: 10 additions & 7 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 All @@ -32,6 +34,9 @@ static void secp256k1_num_set_bin(secp256k1_num *r, const unsigned char *a, unsi
/** Compute a modular inverse. The input must be less than the modulus. */
static void secp256k1_num_mod_inverse(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *m);

/** Compute the jacobi symbol (a|b). b must be positive and odd. */
static int secp256k1_num_jacobi(const secp256k1_num *a, const secp256k1_num *b);

/** Compare the absolute value of two numbers. */
static int secp256k1_num_cmp(const secp256k1_num *a, const secp256k1_num *b);

Expand All @@ -44,9 +49,6 @@ static void secp256k1_num_add(secp256k1_num *r, const secp256k1_num *a, const se
/** Subtract two (signed) numbers. */
static void secp256k1_num_sub(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b);

/** Multiply two (signed) numbers. */
static void secp256k1_num_mul(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b);

/** Replace a number by its remainder modulo m. M's sign is ignored. The result is a number between 0 and m-1,
even if r was negative. */
static void secp256k1_num_mod(secp256k1_num *r, const secp256k1_num *m);
Expand All @@ -57,12 +59,13 @@ static void secp256k1_num_shift(secp256k1_num *r, int bits);
/** Check whether a number is zero. */
static int secp256k1_num_is_zero(const secp256k1_num *a);

/** Check whether a number is one. */
static int secp256k1_num_is_one(const secp256k1_num *a);

/** Check whether a number is strictly negative. */
static int secp256k1_num_is_neg(const secp256k1_num *a);

/** Change a number's sign. */
static void secp256k1_num_negate(secp256k1_num *r);

#endif

#endif
29 changes: 29 additions & 0 deletions src/num_5x64.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/**********************************************************************
* 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
#define NUM_WORD_CTZ __builtin_ctzl
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
41 changes: 41 additions & 0 deletions src/num_5x64_impl.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/**********************************************************************
* 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_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
29 changes: 29 additions & 0 deletions src/num_9x32.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/**********************************************************************
* 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
#define NUM_WORD_CTZ __builtin_ctz
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
49 changes: 49 additions & 0 deletions src/num_9x32_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_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_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
Loading