From 04e34d18c37e0cbcea8094c299c27af240237b8b Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Mon, 8 Sep 2014 23:09:06 +0200 Subject: [PATCH 1/2] Split up signing and verification initialization --- include/secp256k1.h | 12 +++++++++-- src/ecmult_impl.h | 28 ++++++++++++++++++++++++-- src/java/org_bitcoin_NativeSecp256k1.c | 2 +- src/secp256k1.c | 27 +++++++++++++++++++++---- src/tests.c | 2 +- 5 files changed, 61 insertions(+), 10 deletions(-) diff --git a/include/secp256k1.h b/include/secp256k1.h index fd6d6b1..a8ddf43 100644 --- a/include/secp256k1.h +++ b/include/secp256k1.h @@ -5,12 +5,16 @@ extern "C" { #endif +/** Flags to pass to secp256k1_start. */ +#define SECP256K1_START_VERIFY (1 << 0) +#define SECP256K1_START_SIGN (1 << 1) + /** Initialize the library. This may take some time (10-100 ms). * You need to call this before calling any other function. * It cannot run in parallel with any other functions, but once * secp256k1_start() returns, all other functions are thread-safe. */ -void secp256k1_start(void); +void secp256k1_start(unsigned int flags); /** Free all memory associated with this library. After this, no * functions can be called anymore, except secp256k1_start() @@ -22,6 +26,7 @@ void secp256k1_stop(void); * 0: incorrect signature * -1: invalid public key * -2: invalid signature + * Requires starting using SECP256K1_START_VERIFY. */ int secp256k1_ecdsa_verify(const unsigned char *msg, int msglen, const unsigned char *sig, int siglen, @@ -36,6 +41,7 @@ int secp256k1_ecdsa_verify(const unsigned char *msg, int msglen, * nonce: pointer to a 32-byte nonce (generated with a cryptographic PRNG) * Out: sig: pointer to a 72-byte array where the signature will be placed. * siglen: pointer to an int, which will be updated to the signature length (<=72). + * Requires starting using SECP256K1_START_SIGN. */ int secp256k1_ecdsa_sign(const unsigned char *msg, int msglen, unsigned char *sig, int *siglen, @@ -51,6 +57,7 @@ int secp256k1_ecdsa_sign(const unsigned char *msg, int msglen, * nonce: pointer to a 32-byte nonce (generated with a cryptographic PRNG) * Out: sig: pointer to a 64-byte array where the signature will be placed. * recid: pointer to an int, which will be updated to contain the recovery id. + * Requires starting using SECP256K1_START_SIGN. */ int secp256k1_ecdsa_sign_compact(const unsigned char *msg, int msglen, unsigned char *sig64, @@ -68,8 +75,8 @@ int secp256k1_ecdsa_sign_compact(const unsigned char *msg, int msglen, * recid: the recovery id (as returned by ecdsa_sign_compact) * Out: pubkey: pointer to a 33 or 65 byte array to put the pubkey. * pubkeylen: pointer to an int that will contain the pubkey length. + * Requires starting using SECP256K1_START_VERIFY. */ - int secp256k1_ecdsa_recover_compact(const unsigned char *msg, int msglen, const unsigned char *sig64, unsigned char *pubkey, int *pubkeylen, @@ -97,6 +104,7 @@ int secp256k1_ecdsa_pubkey_verify(const unsigned char *pubkey, int pubkeylen); * length. * Returns: 1: secret was valid, public key stores * 0: secret was invalid, try again. + * Requires starting using SECP256K1_START_SIGN. */ int secp256k1_ecdsa_pubkey_create(unsigned char *pubkey, int *pubkeylen, const unsigned char *seckey, int compressed); diff --git a/src/ecmult_impl.h b/src/ecmult_impl.h index b313b6c..c09cfec 100644 --- a/src/ecmult_impl.h +++ b/src/ecmult_impl.h @@ -69,7 +69,9 @@ typedef struct { // For accelerating the computation of a*P + b*G: secp256k1_ge_t pre_g[ECMULT_TABLE_SIZE(WINDOW_G)]; // odd multiples of the generator secp256k1_ge_t pre_g_128[ECMULT_TABLE_SIZE(WINDOW_G)]; // odd multiples of 2^128*generator +} secp256k1_ecmult_consts_t; +typedef struct { // For accelerating the computation of a*G: // To harden against timing attacks, use the following mechanism: // * Break up the multiplicand into groups of 4 bits, called n_0, n_1, n_2, ..., n_63. @@ -83,9 +85,10 @@ typedef struct { // the intermediate sums while computing a*G. // To make memory access uniform, the bytes of prec(i, n_i) are sliced per value of n_i. unsigned char prec[64][sizeof(secp256k1_ge_t)][16]; // prec[j][k][i] = k'th byte of (16^j * i * G + U_i) -} secp256k1_ecmult_consts_t; +} secp256k1_ecmult_gen_consts_t; static const secp256k1_ecmult_consts_t *secp256k1_ecmult_consts = NULL; +static const secp256k1_ecmult_gen_consts_t *secp256k1_ecmult_gen_consts = NULL; static void secp256k1_ecmult_start(void) { if (secp256k1_ecmult_consts != NULL) @@ -106,6 +109,18 @@ static void secp256k1_ecmult_start(void) { // precompute the tables with odd multiples secp256k1_ecmult_table_precomp_ge(ret->pre_g, &gj, WINDOW_G); secp256k1_ecmult_table_precomp_ge(ret->pre_g_128, &g_128j, WINDOW_G); +} + +static void secp256k1_ecmult_gen_start(void) { + if (secp256k1_ecmult_gen_consts != NULL) + return; + + secp256k1_ecmult_gen_consts_t *ret = (secp256k1_ecmult_gen_consts_t*)malloc(sizeof(secp256k1_ecmult_gen_consts_t)); + secp256k1_ecmult_gen_consts = ret; + + // get the generator + const secp256k1_ge_t *g = &secp256k1_ge_consts->g; + secp256k1_gej_t gj; secp256k1_gej_set_ge(&gj, g); // Construct a group element with no known corresponding scalar (nothing up my sleeve). secp256k1_gej_t nums_gej; @@ -165,6 +180,15 @@ static void secp256k1_ecmult_stop(void) { secp256k1_ecmult_consts = NULL; } +static void secp256k1_ecmult_gen_stop(void) { + if (secp256k1_ecmult_gen_consts == NULL) + return; + + secp256k1_ecmult_gen_consts_t *c = (secp256k1_ecmult_gen_consts_t*)secp256k1_ecmult_gen_consts; + free(c); + secp256k1_ecmult_gen_consts = NULL; +} + /** Convert a number to WNAF notation. The number becomes represented by sum(2^i * wnaf[i], i=0..bits), * with the following guarantees: * - each wnaf[i] is either 0, or an odd integer between -(1<<(w-1) - 1) and (1<<(w-1) - 1) @@ -209,7 +233,7 @@ void static secp256k1_ecmult_gen(secp256k1_gej_t *r, const secp256k1_num_t *gn) secp256k1_num_t n; secp256k1_num_init(&n); secp256k1_num_copy(&n, gn); - const secp256k1_ecmult_consts_t *c = secp256k1_ecmult_consts; + const secp256k1_ecmult_gen_consts_t *c = secp256k1_ecmult_gen_consts; secp256k1_gej_set_infinity(r); secp256k1_ge_t add; int bits; diff --git a/src/java/org_bitcoin_NativeSecp256k1.c b/src/java/org_bitcoin_NativeSecp256k1.c index ed65ccc..bb4cd70 100644 --- a/src/java/org_bitcoin_NativeSecp256k1.c +++ b/src/java/org_bitcoin_NativeSecp256k1.c @@ -15,7 +15,7 @@ static void __javasecp256k1_attach(void) __attribute__((constructor)); static void __javasecp256k1_detach(void) __attribute__((destructor)); static void __javasecp256k1_attach(void) { - secp256k1_start(); + secp256k1_start(SECP256K1_START_VERIFY); } static void __javasecp256k1_detach(void) { diff --git a/src/secp256k1.c b/src/secp256k1.c index 65ba146..1a6854e 100644 --- a/src/secp256k1.c +++ b/src/secp256k1.c @@ -2,6 +2,8 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include "include/secp256k1.h" + #include #include "util.h" #include "num_impl.h" @@ -10,19 +12,26 @@ #include "ecmult_impl.h" #include "ecdsa_impl.h" -void secp256k1_start(void) { +void secp256k1_start(unsigned int flags) { secp256k1_fe_start(); secp256k1_ge_start(); - secp256k1_ecmult_start(); + if (flags & SECP256K1_START_SIGN) { + secp256k1_ecmult_gen_start(); + } + if (flags & SECP256K1_START_VERIFY) { + secp256k1_ecmult_start(); + } } void secp256k1_stop(void) { secp256k1_ecmult_stop(); + secp256k1_ecmult_gen_stop(); secp256k1_ge_stop(); secp256k1_fe_stop(); } int secp256k1_ecdsa_verify(const unsigned char *msg, int msglen, const unsigned char *sig, int siglen, const unsigned char *pubkey, int pubkeylen) { + DEBUG_CHECK(secp256k1_ecmult_consts != NULL); DEBUG_CHECK(msg != NULL); DEBUG_CHECK(msglen <= 32); DEBUG_CHECK(sig != NULL); @@ -56,6 +65,7 @@ end: } int secp256k1_ecdsa_sign(const unsigned char *message, int messagelen, unsigned char *signature, int *signaturelen, const unsigned char *seckey, const unsigned char *nonce) { + DEBUG_CHECK(secp256k1_ecmult_gen_consts != NULL); DEBUG_CHECK(message != NULL); DEBUG_CHECK(messagelen <= 32); DEBUG_CHECK(signature != NULL); @@ -91,6 +101,7 @@ int secp256k1_ecdsa_sign(const unsigned char *message, int messagelen, unsigned } int secp256k1_ecdsa_sign_compact(const unsigned char *message, int messagelen, unsigned char *sig64, const unsigned char *seckey, const unsigned char *nonce, int *recid) { + DEBUG_CHECK(secp256k1_ecmult_gen_consts != NULL); DEBUG_CHECK(message != NULL); DEBUG_CHECK(messagelen <= 32); DEBUG_CHECK(sig64 != NULL); @@ -126,6 +137,7 @@ int secp256k1_ecdsa_sign_compact(const unsigned char *message, int messagelen, u } int secp256k1_ecdsa_recover_compact(const unsigned char *msg, int msglen, const unsigned char *sig64, unsigned char *pubkey, int *pubkeylen, int compressed, int recid) { + DEBUG_CHECK(secp256k1_ecmult_consts != NULL); DEBUG_CHECK(msg != NULL); DEBUG_CHECK(msglen <= 32); DEBUG_CHECK(sig64 != NULL); @@ -173,6 +185,7 @@ int secp256k1_ecdsa_pubkey_verify(const unsigned char *pubkey, int pubkeylen) { } int secp256k1_ecdsa_pubkey_create(unsigned char *pubkey, int *pubkeylen, const unsigned char *seckey, int compressed) { + DEBUG_CHECK(secp256k1_ecmult_gen_consts != NULL); DEBUG_CHECK(pubkey != NULL); DEBUG_CHECK(pubkeylen != NULL); DEBUG_CHECK(seckey != NULL); @@ -230,6 +243,7 @@ int secp256k1_ecdsa_privkey_tweak_add(unsigned char *seckey, const unsigned char } int secp256k1_ecdsa_pubkey_tweak_add(unsigned char *pubkey, int pubkeylen, const unsigned char *tweak) { + DEBUG_CHECK(secp256k1_ecmult_consts != NULL); DEBUG_CHECK(pubkey != NULL); DEBUG_CHECK(tweak != NULL); @@ -246,8 +260,12 @@ int secp256k1_ecdsa_pubkey_tweak_add(unsigned char *pubkey, int pubkeylen, const } if (ret) { secp256k1_gej_t pt; - secp256k1_ecmult_gen(&pt, &term); - secp256k1_gej_add_ge(&pt, &pt, &p); + secp256k1_gej_set_ge(&pt, &p); + secp256k1_num_t one; + secp256k1_num_init(&one); + secp256k1_num_set_int(&one, 1); + secp256k1_ecmult(&pt, &pt, &one, &term); + secp256k1_num_free(&one); if (secp256k1_gej_is_infinity(&pt)) ret = 0; secp256k1_ge_set_gej(&p, &pt); @@ -285,6 +303,7 @@ int secp256k1_ecdsa_privkey_tweak_mul(unsigned char *seckey, const unsigned char } int secp256k1_ecdsa_pubkey_tweak_mul(unsigned char *pubkey, int pubkeylen, const unsigned char *tweak) { + DEBUG_CHECK(secp256k1_ecmult_consts != NULL); DEBUG_CHECK(pubkey != NULL); DEBUG_CHECK(tweak != NULL); diff --git a/src/tests.c b/src/tests.c index b8f3c08..80ae0f4 100644 --- a/src/tests.c +++ b/src/tests.c @@ -704,7 +704,7 @@ int main(int argc, char **argv) { printf("test count = %i\n", count); // initialize - secp256k1_start(); + secp256k1_start(SECP256K1_START_SIGN | SECP256K1_START_VERIFY); // num tests run_num_smalltests(); From c259a7cbc0d93fe70dd3fea3d26ab95dbbf1a618 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Sat, 13 Sep 2014 17:19:26 +0200 Subject: [PATCH 2/2] Set precomputation table late and unset early. Set the global pointer to the precomputation table only after initializing it completely, and unset it before doing any uninitialization. This causes fail-fast behavior in case of race conditions between initialization and operations using it. --- src/ecmult_impl.h | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/ecmult_impl.h b/src/ecmult_impl.h index c09cfec..1b575aa 100644 --- a/src/ecmult_impl.h +++ b/src/ecmult_impl.h @@ -94,8 +94,8 @@ static void secp256k1_ecmult_start(void) { if (secp256k1_ecmult_consts != NULL) return; + // Allocate the precomputation table. secp256k1_ecmult_consts_t *ret = (secp256k1_ecmult_consts_t*)malloc(sizeof(secp256k1_ecmult_consts_t)); - secp256k1_ecmult_consts = ret; // get the generator const secp256k1_ge_t *g = &secp256k1_ge_consts->g; @@ -109,14 +109,17 @@ static void secp256k1_ecmult_start(void) { // precompute the tables with odd multiples secp256k1_ecmult_table_precomp_ge(ret->pre_g, &gj, WINDOW_G); secp256k1_ecmult_table_precomp_ge(ret->pre_g_128, &g_128j, WINDOW_G); + + // Set the global pointer to the precomputation table. + secp256k1_ecmult_consts = ret; } static void secp256k1_ecmult_gen_start(void) { if (secp256k1_ecmult_gen_consts != NULL) return; + // Allocate the precomputation table. secp256k1_ecmult_gen_consts_t *ret = (secp256k1_ecmult_gen_consts_t*)malloc(sizeof(secp256k1_ecmult_gen_consts_t)); - secp256k1_ecmult_gen_consts = ret; // get the generator const secp256k1_ge_t *g = &secp256k1_ge_consts->g; @@ -169,6 +172,9 @@ static void secp256k1_ecmult_gen_start(void) { ret->prec[j][k][i] = raw[k]; } } + + // Set the global pointer to the precomputation table. + secp256k1_ecmult_gen_consts = ret; } static void secp256k1_ecmult_stop(void) { @@ -176,8 +182,8 @@ static void secp256k1_ecmult_stop(void) { return; secp256k1_ecmult_consts_t *c = (secp256k1_ecmult_consts_t*)secp256k1_ecmult_consts; - free(c); secp256k1_ecmult_consts = NULL; + free(c); } static void secp256k1_ecmult_gen_stop(void) { @@ -185,8 +191,8 @@ static void secp256k1_ecmult_gen_stop(void) { return; secp256k1_ecmult_gen_consts_t *c = (secp256k1_ecmult_gen_consts_t*)secp256k1_ecmult_gen_consts; - free(c); secp256k1_ecmult_gen_consts = NULL; + free(c); } /** Convert a number to WNAF notation. The number becomes represented by sum(2^i * wnaf[i], i=0..bits),