From a591d98c322093040d59e152591f0978962f9da7 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Wed, 22 Apr 2015 14:03:10 -0700 Subject: [PATCH 1/2] Squashed 'src/secp256k1/' changes from 1897b8e..22f60a6 22f60a6 Merge pull request #245 61c1b1e Merge pull request #190 d227579 Add scalar blinding and a secp256k1_context_randomize() call. c146b4a Add bench_internal to gitignore. 9c4fb23 Add a secp256k1_fe_cmov unit test. 426fa52 Merge pull request #243 d505a89 Merge pull request #244 2d2707a travis: test i686 builds with gmp cf7f702 travis: update to new build infrastructure bb0ea50 Replace set/add with cmov in secp256k1_gej_add_ge. f3d3519 Merge pull request #241 5c2a4fa Fix memory leak in context unit test 14aacdc Merge pull request #239 93226a5 secp256k1.c: Add missing DEBUG_CHECKs for sufficiently capable contexts 6099220 Merge pull request #237 6066bb6 Fix typo: avg -> max 9688030 Merge pull request #236 d899b5b Expose ability to deep-copy a context 3608c7f Merge pull request #208 a9b6595 [API BREAK] Introduce explicit contexts a0d3b89 Merge pull request #233 9e8d89b Merge pull request #234 65e70e7 Merge pull request #235 5098f62 Improve documentation formatting consistency 4450e24 Add a comment about the avoidance of secret data in array indexes. 6534ee1 initialize variable d5b53aa Merge pull request #232 c01df1a Avoid some implicit type conversions to make C++ compilers happy. bfe96ba Merge pull request #231 33270bf Add a couple comments pointing to particular sections of RFC6979. 41603aa Merge pull request #230 2632019 Brace all the if/for/while. git-subtree-dir: src/secp256k1 git-subtree-split: 22f60a62801a8a49ecd049e7a563f69a41affd8d --- .gitignore | 1 + .travis.yml | 41 +++- include/secp256k1.h | 154 +++++++++----- src/bench.h | 2 +- src/bench_recover.c | 8 +- src/bench_sign.c | 8 +- src/bench_verify.c | 11 +- src/ecdsa.h | 7 +- src/ecdsa_impl.h | 84 +++++--- src/eckey.h | 8 +- src/eckey_impl.h | 48 +++-- src/ecmult.h | 18 +- src/ecmult_gen.h | 30 ++- src/ecmult_gen_impl.h | 140 +++++++++---- src/ecmult_impl.h | 115 +++++++---- src/field.h | 3 + src/field_10x26_impl.h | 31 ++- src/field_5x52_impl.h | 26 ++- src/field_impl.h | 99 ++++++--- src/group.h | 3 + src/group_impl.h | 41 ++-- src/hash_impl.h | 15 +- src/num_gmp_impl.h | 49 +++-- src/scalar_impl.h | 114 +++++++---- src/secp256k1.c | 125 ++++++++---- src/tests.c | 453 +++++++++++++++++++++++++++++------------ 26 files changed, 1160 insertions(+), 474 deletions(-) diff --git a/.gitignore b/.gitignore index b9f7d243e..076ff1295 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ bench_inv bench_sign bench_verify bench_recover +bench_internal tests *.exe *.so diff --git a/.travis.yml b/.travis.yml index 40f8dae23..0d8089cfe 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,14 +1,14 @@ language: c +sudo: false +addons: + apt: + packages: libgmp-dev compiler: - clang - gcc -install: - - sudo apt-get install -qq libssl-dev - - if [ "$BIGNUM" = "gmp" -o "$BIGNUM" = "auto" ]; then sudo apt-get install --no-install-recommends --no-upgrade -qq libgmp-dev; fi - - if [ -n "$EXTRAPACKAGES" ]; then sudo apt-get update && sudo apt-get install --no-install-recommends --no-upgrade $EXTRAPACKAGES; fi env: global: - - FIELD=auto BIGNUM=auto SCALAR=auto ENDOMORPHISM=no ASM=no BUILD=check EXTRAFLAGS= HOST= EXTRAPACKAGES= + - FIELD=auto BIGNUM=auto SCALAR=auto ENDOMORPHISM=no ASM=no BUILD=check EXTRAFLAGS= HOST= matrix: - SCALAR=32bit - SCALAR=64bit @@ -22,8 +22,35 @@ env: - BIGNUM=no ENDOMORPHISM=yes - BUILD=distcheck - EXTRAFLAGS=CFLAGS=-DDETERMINISTIC - - HOST=i686-linux-gnu EXTRAPACKAGES="gcc-multilib" - - HOST=i686-linux-gnu EXTRAPACKAGES="gcc-multilib" ENDOMORPHISM=yes +matrix: + fast_finish: true + include: + - compiler: clang + env: HOST=i686-linux-gnu ENDOMORPHISM=yes + addons: + apt: + packages: + - gcc-multilib + - libgmp-dev:i386 + - compiler: clang + env: HOST=i686-linux-gnu + addons: + apt: + packages: + - gcc-multilib + - compiler: gcc + env: HOST=i686-linux-gnu ENDOMORPHISM=yes + addons: + apt: + packages: + - gcc-multilib + - compiler: gcc + env: HOST=i686-linux-gnu + addons: + apt: + packages: + - gcc-multilib + - libgmp-dev:i386 before_script: ./autogen.sh script: - if [ -n "$HOST" ]; then export USE_HOST="--host=$HOST"; fi diff --git a/include/secp256k1.h b/include/secp256k1.h index a6e39d13d..06afd4c65 100644 --- a/include/secp256k1.h +++ b/include/secp256k1.h @@ -40,42 +40,60 @@ extern "C" { # define SECP256K1_ARG_NONNULL(_x) # 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. +/** Opaque data structure that holds context information (precomputed tables etc.). + * Only functions that take a pointer to a non-const context require exclusive + * access to it. Multiple functions that take a pointer to a const context may + * run simultaneously. */ -void secp256k1_start(unsigned int flags); +typedef struct secp256k1_context_struct secp256k1_context_t; -/** Free all memory associated with this library. After this, no - * functions can be called anymore, except secp256k1_start() +/** Flags to pass to secp256k1_context_create. */ +# define SECP256K1_CONTEXT_VERIFY (1 << 0) +# define SECP256K1_CONTEXT_SIGN (1 << 1) + +/** Create a secp256k1 context object. + * Returns: a newly created context object. + * In: flags: which parts of the context to initialize. */ -void secp256k1_stop(void); +secp256k1_context_t* secp256k1_context_create( + int flags +) SECP256K1_WARN_UNUSED_RESULT; + +/** Copies a secp256k1 context object. + * Returns: a newly created context object. + * In: ctx: an existing context to copy + */ +secp256k1_context_t* secp256k1_context_clone( + const secp256k1_context_t* ctx +) SECP256K1_WARN_UNUSED_RESULT; + +/** Destroy a secp256k1 context object. + * The context pointer may not be used afterwards. + */ +void secp256k1_context_destroy( + secp256k1_context_t* ctx +) SECP256K1_ARG_NONNULL(1); /** Verify an ECDSA signature. * Returns: 1: correct signature * 0: incorrect signature * -1: invalid public key * -2: invalid signature - * In: msg32: the 32-byte message hash being verified (cannot be NULL) + * In: ctx: a secp256k1 context object, initialized for verification. + * msg32: the 32-byte message hash being verified (cannot be NULL) * sig: the signature being verified (cannot be NULL) * siglen: the length of the signature * pubkey: the public key to verify with (cannot be NULL) * pubkeylen: the length of pubkey - * Requires starting using SECP256K1_START_VERIFY. */ SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_verify( + const secp256k1_context_t* ctx, const unsigned char *msg32, const unsigned char *sig, int siglen, const unsigned char *pubkey, int pubkeylen -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4); +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5); /** A pointer to a function to deterministically generate a nonce. * Returns: 1 if a nonce was successfully generated. 0 will cause signing to fail. @@ -111,15 +129,14 @@ extern const secp256k1_nonce_function_t secp256k1_nonce_function_default; * Returns: 1: signature created * 0: the nonce generation function failed, the private key was invalid, or there is not * enough space in the signature (as indicated by siglen). - * In: msg32: the 32-byte message hash being signed (cannot be NULL) + * In: ctx: pointer to a context object, initialized for signing (cannot be NULL) + * msg32: the 32-byte message hash being signed (cannot be NULL) * seckey: pointer to a 32-byte secret key (cannot be NULL) * noncefp:pointer to a nonce generation function. If NULL, secp256k1_nonce_function_default is used * ndata: pointer to arbitrary data used by the nonce generation function (can be NULL) * Out: sig: pointer to an array where the signature will be placed (cannot be NULL) * In/Out: siglen: pointer to an int with the length of sig, which will be updated - * to contain the actual signature length (<=72). If 0 is returned, this will be - * set to zero. - * Requires starting using SECP256K1_START_SIGN. + * to contain the actual signature length (<=72). * * The sig always has an s value in the lower half of the range (From 0x1 * to 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0, @@ -148,145 +165,180 @@ extern const secp256k1_nonce_function_t secp256k1_nonce_function_default; * be taken when this property is required for an application. */ int secp256k1_ecdsa_sign( + const secp256k1_context_t* ctx, const unsigned char *msg32, unsigned char *sig, int *siglen, const unsigned char *seckey, secp256k1_nonce_function_t noncefp, const void *ndata -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5); /** Create a compact ECDSA signature (64 byte + recovery id). * Returns: 1: signature created * 0: the nonce generation function failed, or the secret key was invalid. - * In: msg32: the 32-byte message hash being signed (cannot be NULL) + * In: ctx: pointer to a context object, initialized for signing (cannot be NULL) + * msg32: the 32-byte message hash being signed (cannot be NULL) * seckey: pointer to a 32-byte secret key (cannot be NULL) * noncefp:pointer to a nonce generation function. If NULL, secp256k1_nonce_function_default is used * ndata: pointer to arbitrary data used by the nonce generation function (can be NULL) * Out: sig: pointer to a 64-byte array where the signature will be placed (cannot be NULL) * In case 0 is returned, the returned signature length will be zero. * recid: pointer to an int, which will be updated to contain the recovery id (can be NULL) - * Requires starting using SECP256K1_START_SIGN. */ int secp256k1_ecdsa_sign_compact( + const secp256k1_context_t* ctx, const unsigned char *msg32, unsigned char *sig64, const unsigned char *seckey, secp256k1_nonce_function_t noncefp, const void *ndata, int *recid -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); /** Recover an ECDSA public key from a compact signature. * Returns: 1: public key successfully recovered (which guarantees a correct signature). * 0: otherwise. - * In: msg32: the 32-byte message hash assumed to be signed (cannot be NULL) + * In: ctx: pointer to a context object, initialized for verification (cannot be NULL) + * msg32: the 32-byte message hash assumed to be signed (cannot be NULL) * sig64: signature as 64 byte array (cannot be NULL) * compressed: whether to recover a compressed or uncompressed pubkey * recid: the recovery id (0-3, as returned by ecdsa_sign_compact) * Out: pubkey: pointer to a 33 or 65 byte array to put the pubkey (cannot be NULL) * pubkeylen: pointer to an int that will contain the pubkey length (cannot be NULL) - * Requires starting using SECP256K1_START_VERIFY. */ SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_recover_compact( + const secp256k1_context_t* ctx, const unsigned char *msg32, const unsigned char *sig64, unsigned char *pubkey, int *pubkeylen, int compressed, int recid -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5); /** Verify an ECDSA secret key. * Returns: 1: secret key is valid * 0: secret key is invalid - * In: seckey: pointer to a 32-byte secret key (cannot be NULL) + * In: ctx: pointer to a context object (cannot be NULL) + * seckey: pointer to a 32-byte secret key (cannot be NULL) */ -SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_verify(const unsigned char *seckey) SECP256K1_ARG_NONNULL(1); +SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_verify( + const secp256k1_context_t* ctx, + const unsigned char *seckey +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); /** Just validate a public key. - * Returns: 1: valid public key - * 0: invalid public key - * In: pubkey: pointer to a 33-byte or 65-byte public key (cannot be NULL). + * Returns: 1: public key is valid + * 0: public key is invalid + * In: ctx: pointer to a context object (cannot be NULL) + * pubkey: pointer to a 33-byte or 65-byte public key (cannot be NULL). * pubkeylen: length of pubkey */ -SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_verify(const unsigned char *pubkey, int pubkeylen) SECP256K1_ARG_NONNULL(1); +SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_verify( + const secp256k1_context_t* ctx, + const unsigned char *pubkey, + int pubkeylen +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); /** Compute the public key for a secret key. - * In: compressed: whether the computed public key should be compressed + * In: ctx: pointer to a context object, initialized for signing (cannot be NULL) + * compressed: whether the computed public key should be compressed * seckey: pointer to a 32-byte private key (cannot be NULL) * Out: pubkey: pointer to a 33-byte (if compressed) or 65-byte (if uncompressed) * area to store the public key (cannot be NULL) * pubkeylen: pointer to int that will be updated to contains the pubkey's * length (cannot be NULL) * Returns: 1: secret was valid, public key stores - * 0: secret was invalid, try again. - * Requires starting using SECP256K1_START_SIGN. + * 0: secret was invalid, try again */ SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_create( + const secp256k1_context_t* ctx, unsigned char *pubkey, int *pubkeylen, const unsigned char *seckey, int compressed -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); /** Decompress a public key. + * In: ctx: pointer to a context object (cannot be NULL) * In/Out: pubkey: pointer to a 65-byte array to put the decompressed public key. - It must contain a 33-byte or 65-byte public key already (cannot be NULL) + * It must contain a 33-byte or 65-byte public key already (cannot be NULL) * pubkeylen: pointer to the size of the public key pointed to by pubkey (cannot be NULL) - It will be updated to reflect the new size. - * Returns: 0 if the passed public key was invalid, 1 otherwise. If 1 is returned, the - pubkey is replaced with its decompressed version. + * It will be updated to reflect the new size. + * Returns: 0: pubkey was invalid + * 1: pubkey was valid, and was replaced with its decompressed version */ SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_decompress( + const secp256k1_context_t* ctx, unsigned char *pubkey, int *pubkeylen -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); -/** Export a private key in DER format. */ +/** Export a private key in DER format. + * In: ctx: pointer to a context object, initialized for signing (cannot be NULL) + */ SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_export( + const secp256k1_context_t* ctx, const unsigned char *seckey, unsigned char *privkey, int *privkeylen, int compressed -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); /** Import a private key in DER format. */ SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_import( + const secp256k1_context_t* ctx, unsigned char *seckey, const unsigned char *privkey, int privkeylen -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); /** Tweak a private key by adding tweak to it. */ SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_add( + const secp256k1_context_t* ctx, unsigned char *seckey, const unsigned char *tweak -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); /** Tweak a public key by adding tweak times the generator to it. - * Requires starting with SECP256K1_START_VERIFY. + * In: ctx: pointer to a context object, initialized for verification (cannot be NULL) */ SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_add( + const secp256k1_context_t* ctx, unsigned char *pubkey, int pubkeylen, const unsigned char *tweak -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3); +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4); /** Tweak a private key by multiplying it with tweak. */ SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_mul( + const secp256k1_context_t* ctx, unsigned char *seckey, const unsigned char *tweak -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); /** Tweak a public key by multiplying it with tweak. - * Requires starting with SECP256K1_START_VERIFY. + * In: ctx: pointer to a context object, initialized for verification (cannot be NULL) */ SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_mul( + const secp256k1_context_t* ctx, unsigned char *pubkey, int pubkeylen, const unsigned char *tweak -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3); +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4); + +/** Updates the context randomization. + * Returns: 1: randomization successfully updated + * 0: error + * In: ctx: pointer to a context object (cannot be NULL) + * seed32: pointer to a 32-byte random seed (NULL resets to initial state) + */ +SECP256K1_WARN_UNUSED_RESULT int secp256k1_context_randomize( + secp256k1_context_t* ctx, + const unsigned char *seed32 +) SECP256K1_ARG_NONNULL(1); + # ifdef __cplusplus } diff --git a/src/bench.h b/src/bench.h index 0559b3e85..db5f68cee 100644 --- a/src/bench.h +++ b/src/bench.h @@ -48,7 +48,7 @@ void run_benchmark(char *name, void (*benchmark)(void*), void (*setup)(void*), v print_number(min * 1000000.0 / iter); printf("us / avg "); print_number((sum / count) * 1000000.0 / iter); - printf("us / avg "); + printf("us / max "); print_number(max * 1000000.0 / iter); printf("us\n"); } diff --git a/src/bench_recover.c b/src/bench_recover.c index 6991cc9d6..56faed11a 100644 --- a/src/bench_recover.c +++ b/src/bench_recover.c @@ -9,6 +9,7 @@ #include "bench.h" typedef struct { + secp256k1_context_t *ctx; unsigned char msg[32]; unsigned char sig[64]; } bench_recover_t; @@ -21,7 +22,7 @@ void bench_recover(void* arg) { for (i = 0; i < 20000; i++) { int j; int pubkeylen = 33; - CHECK(secp256k1_ecdsa_recover_compact(data->msg, data->sig, pubkey, &pubkeylen, 1, i % 2)); + CHECK(secp256k1_ecdsa_recover_compact(data->ctx, data->msg, data->sig, pubkey, &pubkeylen, 1, i % 2)); for (j = 0; j < 32; j++) { data->sig[j + 32] = data->msg[j]; /* Move former message to S. */ data->msg[j] = data->sig[j]; /* Move former R to message. */ @@ -40,10 +41,11 @@ void bench_recover_setup(void* arg) { int main(void) { bench_recover_t data; - secp256k1_start(SECP256K1_START_VERIFY); + + data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY); run_benchmark("ecdsa_recover", bench_recover, bench_recover_setup, NULL, &data, 10, 20000); - secp256k1_stop(); + secp256k1_context_destroy(data.ctx); return 0; } diff --git a/src/bench_sign.c b/src/bench_sign.c index c5b6829a8..072a37af5 100644 --- a/src/bench_sign.c +++ b/src/bench_sign.c @@ -9,6 +9,7 @@ #include "bench.h" typedef struct { + secp256k1_context_t* ctx; unsigned char msg[32]; unsigned char key[32]; } bench_sign_t; @@ -29,7 +30,7 @@ static void bench_sign(void* arg) { for (i = 0; i < 20000; i++) { int j; int recid = 0; - CHECK(secp256k1_ecdsa_sign_compact(data->msg, sig, data->key, NULL, NULL, &recid)); + CHECK(secp256k1_ecdsa_sign_compact(data->ctx, data->msg, sig, data->key, NULL, NULL, &recid)); for (j = 0; j < 32; j++) { data->msg[j] = sig[j]; /* Move former R to message. */ data->key[j] = sig[j + 32]; /* Move former S to key. */ @@ -39,10 +40,11 @@ static void bench_sign(void* arg) { int main(void) { bench_sign_t data; - secp256k1_start(SECP256K1_START_SIGN); + + data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); run_benchmark("ecdsa_sign", bench_sign, bench_sign_setup, NULL, &data, 10, 20000); - secp256k1_stop(); + secp256k1_context_destroy(data.ctx); return 0; } diff --git a/src/bench_verify.c b/src/bench_verify.c index c279305a0..c8c82752c 100644 --- a/src/bench_verify.c +++ b/src/bench_verify.c @@ -12,6 +12,7 @@ #include "bench.h" typedef struct { + secp256k1_context_t *ctx; unsigned char msg[32]; unsigned char key[32]; unsigned char sig[72]; @@ -28,7 +29,7 @@ static void benchmark_verify(void* arg) { data->sig[data->siglen - 1] ^= (i & 0xFF); data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF); data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF); - CHECK(secp256k1_ecdsa_verify(data->msg, data->sig, data->siglen, data->pubkey, data->pubkeylen) == (i == 0)); + CHECK(secp256k1_ecdsa_verify(data->ctx, data->msg, data->sig, data->siglen, data->pubkey, data->pubkeylen) == (i == 0)); data->sig[data->siglen - 1] ^= (i & 0xFF); data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF); data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF); @@ -39,17 +40,17 @@ int main(void) { int i; benchmark_verify_t data; - secp256k1_start(SECP256K1_START_VERIFY | SECP256K1_START_SIGN); + data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); for (i = 0; i < 32; i++) data.msg[i] = 1 + i; for (i = 0; i < 32; i++) data.key[i] = 33 + i; data.siglen = 72; - secp256k1_ecdsa_sign(data.msg, data.sig, &data.siglen, data.key, NULL, NULL); + secp256k1_ecdsa_sign(data.ctx, data.msg, data.sig, &data.siglen, data.key, NULL, NULL); data.pubkeylen = 33; - CHECK(secp256k1_ec_pubkey_create(data.pubkey, &data.pubkeylen, data.key, 1)); + CHECK(secp256k1_ec_pubkey_create(data.ctx, data.pubkey, &data.pubkeylen, data.key, 1)); run_benchmark("ecdsa_verify", benchmark_verify, NULL, NULL, &data, 10, 20000); - secp256k1_stop(); + secp256k1_context_destroy(data.ctx); return 0; } diff --git a/src/ecdsa.h b/src/ecdsa.h index c195e7afc..4ef78e8af 100644 --- a/src/ecdsa.h +++ b/src/ecdsa.h @@ -9,6 +9,7 @@ #include "scalar.h" #include "group.h" +#include "ecmult.h" typedef struct { secp256k1_scalar_t r, s; @@ -16,8 +17,8 @@ typedef struct { static int secp256k1_ecdsa_sig_parse(secp256k1_ecdsa_sig_t *r, const unsigned char *sig, int size); static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, int *size, const secp256k1_ecdsa_sig_t *a); -static int secp256k1_ecdsa_sig_verify(const secp256k1_ecdsa_sig_t *sig, const secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message); -static int secp256k1_ecdsa_sig_sign(secp256k1_ecdsa_sig_t *sig, const secp256k1_scalar_t *seckey, const secp256k1_scalar_t *message, const secp256k1_scalar_t *nonce, int *recid); -static int secp256k1_ecdsa_sig_recover(const secp256k1_ecdsa_sig_t *sig, secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message, int recid); +static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context_t *ctx, const secp256k1_ecdsa_sig_t *sig, const secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message); +static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context_t *ctx, secp256k1_ecdsa_sig_t *sig, const secp256k1_scalar_t *seckey, const secp256k1_scalar_t *message, const secp256k1_scalar_t *nonce, int *recid); +static int secp256k1_ecdsa_sig_recover(const secp256k1_ecmult_context_t *ctx, const secp256k1_ecdsa_sig_t *sig, secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message, int recid); #endif diff --git a/src/ecdsa_impl.h b/src/ecdsa_impl.h index 1a7764939..ed1d22818 100644 --- a/src/ecdsa_impl.h +++ b/src/ecdsa_impl.h @@ -53,35 +53,59 @@ static int secp256k1_ecdsa_sig_parse(secp256k1_ecdsa_sig_t *r, const unsigned ch int lenr; int lens; int overflow; - if (sig[0] != 0x30) return 0; + if (sig[0] != 0x30) { + return 0; + } lenr = sig[3]; - if (5+lenr >= size) return 0; + if (5+lenr >= size) { + return 0; + } lens = sig[lenr+5]; - if (sig[1] != lenr+lens+4) return 0; - if (lenr+lens+6 > size) return 0; - if (sig[2] != 0x02) return 0; - if (lenr == 0) return 0; - if (sig[lenr+4] != 0x02) return 0; - if (lens == 0) return 0; + if (sig[1] != lenr+lens+4) { + return 0; + } + if (lenr+lens+6 > size) { + return 0; + } + if (sig[2] != 0x02) { + return 0; + } + if (lenr == 0) { + return 0; + } + if (sig[lenr+4] != 0x02) { + return 0; + } + if (lens == 0) { + return 0; + } sp = sig + 6 + lenr; while (lens > 0 && sp[0] == 0) { lens--; sp++; } - if (lens > 32) return 0; + if (lens > 32) { + return 0; + } rp = sig + 4; while (lenr > 0 && rp[0] == 0) { lenr--; rp++; } - if (lenr > 32) return 0; + if (lenr > 32) { + return 0; + } memcpy(ra + 32 - lenr, rp, lenr); memcpy(sa + 32 - lens, sp, lens); overflow = 0; secp256k1_scalar_set_b32(&r->r, ra, &overflow); - if (overflow) return 0; + if (overflow) { + return 0; + } secp256k1_scalar_set_b32(&r->s, sa, &overflow); - if (overflow) return 0; + if (overflow) { + return 0; + } return 1; } @@ -93,8 +117,9 @@ static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, int *size, const se secp256k1_scalar_get_b32(&s[1], &a->s); while (lenR > 1 && rp[0] == 0 && rp[1] < 0x80) { lenR--; rp++; } while (lenS > 1 && sp[0] == 0 && sp[1] < 0x80) { lenS--; sp++; } - if (*size < 6+lenS+lenR) + if (*size < 6+lenS+lenR) { return 0; + } *size = 6 + lenS + lenR; sig[0] = 0x30; sig[1] = 4 + lenS + lenR; @@ -107,21 +132,22 @@ static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, int *size, const se return 1; } -static int secp256k1_ecdsa_sig_verify(const secp256k1_ecdsa_sig_t *sig, const secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message) { +static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context_t *ctx, const secp256k1_ecdsa_sig_t *sig, const secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message) { unsigned char c[32]; secp256k1_scalar_t sn, u1, u2; secp256k1_fe_t xr; secp256k1_gej_t pubkeyj; secp256k1_gej_t pr; - if (secp256k1_scalar_is_zero(&sig->r) || secp256k1_scalar_is_zero(&sig->s)) + if (secp256k1_scalar_is_zero(&sig->r) || secp256k1_scalar_is_zero(&sig->s)) { return 0; + } secp256k1_scalar_inverse_var(&sn, &sig->s); secp256k1_scalar_mul(&u1, &sn, message); secp256k1_scalar_mul(&u2, &sn, &sig->r); secp256k1_gej_set_ge(&pubkeyj, pubkey); - secp256k1_ecmult(&pr, &pubkeyj, &u2, &u1); + secp256k1_ecmult(ctx, &pr, &pubkeyj, &u2, &u1); if (secp256k1_gej_is_infinity(&pr)) { return 0; } @@ -160,7 +186,7 @@ static int secp256k1_ecdsa_sig_verify(const secp256k1_ecdsa_sig_t *sig, const se return 0; } -static int secp256k1_ecdsa_sig_recover(const secp256k1_ecdsa_sig_t *sig, secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message, int recid) { +static int secp256k1_ecdsa_sig_recover(const secp256k1_ecmult_context_t *ctx, const secp256k1_ecdsa_sig_t *sig, secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message, int recid) { unsigned char brx[32]; secp256k1_fe_t fx; secp256k1_ge_t x; @@ -168,36 +194,39 @@ static int secp256k1_ecdsa_sig_recover(const secp256k1_ecdsa_sig_t *sig, secp256 secp256k1_scalar_t rn, u1, u2; secp256k1_gej_t qj; - if (secp256k1_scalar_is_zero(&sig->r) || secp256k1_scalar_is_zero(&sig->s)) + if (secp256k1_scalar_is_zero(&sig->r) || secp256k1_scalar_is_zero(&sig->s)) { return 0; + } secp256k1_scalar_get_b32(brx, &sig->r); VERIFY_CHECK(secp256k1_fe_set_b32(&fx, brx)); /* brx comes from a scalar, so is less than the order; certainly less than p */ if (recid & 2) { - if (secp256k1_fe_cmp_var(&fx, &secp256k1_ecdsa_const_p_minus_order) >= 0) + if (secp256k1_fe_cmp_var(&fx, &secp256k1_ecdsa_const_p_minus_order) >= 0) { return 0; + } secp256k1_fe_add(&fx, &secp256k1_ecdsa_const_order_as_fe); } - if (!secp256k1_ge_set_xo_var(&x, &fx, recid & 1)) + if (!secp256k1_ge_set_xo_var(&x, &fx, recid & 1)) { return 0; + } secp256k1_gej_set_ge(&xj, &x); secp256k1_scalar_inverse_var(&rn, &sig->r); secp256k1_scalar_mul(&u1, &rn, message); secp256k1_scalar_negate(&u1, &u1); secp256k1_scalar_mul(&u2, &rn, &sig->s); - secp256k1_ecmult(&qj, &xj, &u2, &u1); + secp256k1_ecmult(ctx, &qj, &xj, &u2, &u1); secp256k1_ge_set_gej_var(pubkey, &qj); return !secp256k1_gej_is_infinity(&qj); } -static int secp256k1_ecdsa_sig_sign(secp256k1_ecdsa_sig_t *sig, const secp256k1_scalar_t *seckey, const secp256k1_scalar_t *message, const secp256k1_scalar_t *nonce, int *recid) { +static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context_t *ctx, secp256k1_ecdsa_sig_t *sig, const secp256k1_scalar_t *seckey, const secp256k1_scalar_t *message, const secp256k1_scalar_t *nonce, int *recid) { unsigned char b[32]; secp256k1_gej_t rp; secp256k1_ge_t r; secp256k1_scalar_t n; int overflow = 0; - secp256k1_ecmult_gen(&rp, nonce); + secp256k1_ecmult_gen(ctx, &rp, nonce); secp256k1_ge_set_gej(&r, &rp); secp256k1_fe_normalize(&r.x); secp256k1_fe_normalize(&r.y); @@ -209,8 +238,9 @@ static int secp256k1_ecdsa_sig_sign(secp256k1_ecdsa_sig_t *sig, const secp256k1_ secp256k1_ge_clear(&r); return 0; } - if (recid) + if (recid) { *recid = (overflow ? 2 : 0) | (secp256k1_fe_is_odd(&r.y) ? 1 : 0); + } secp256k1_scalar_mul(&n, &sig->r, seckey); secp256k1_scalar_add(&n, &n, message); secp256k1_scalar_inverse(&sig->s, nonce); @@ -218,12 +248,14 @@ static int secp256k1_ecdsa_sig_sign(secp256k1_ecdsa_sig_t *sig, const secp256k1_ secp256k1_scalar_clear(&n); secp256k1_gej_clear(&rp); secp256k1_ge_clear(&r); - if (secp256k1_scalar_is_zero(&sig->s)) + if (secp256k1_scalar_is_zero(&sig->s)) { return 0; + } if (secp256k1_scalar_is_high(&sig->s)) { secp256k1_scalar_negate(&sig->s, &sig->s); - if (recid) + if (recid) { *recid ^= 1; + } } return 1; } diff --git a/src/eckey.h b/src/eckey.h index 6de5dc0a5..53b818485 100644 --- a/src/eckey.h +++ b/src/eckey.h @@ -9,16 +9,18 @@ #include "group.h" #include "scalar.h" +#include "ecmult.h" +#include "ecmult_gen.h" static int secp256k1_eckey_pubkey_parse(secp256k1_ge_t *elem, const unsigned char *pub, int size); static int secp256k1_eckey_pubkey_serialize(secp256k1_ge_t *elem, unsigned char *pub, int *size, int compressed); static int secp256k1_eckey_privkey_parse(secp256k1_scalar_t *key, const unsigned char *privkey, int privkeylen); -static int secp256k1_eckey_privkey_serialize(unsigned char *privkey, int *privkeylen, const secp256k1_scalar_t *key, int compressed); +static int secp256k1_eckey_privkey_serialize(const secp256k1_ecmult_gen_context_t *ctx, unsigned char *privkey, int *privkeylen, const secp256k1_scalar_t *key, int compressed); static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar_t *key, const secp256k1_scalar_t *tweak); -static int secp256k1_eckey_pubkey_tweak_add(secp256k1_ge_t *key, const secp256k1_scalar_t *tweak); +static int secp256k1_eckey_pubkey_tweak_add(const secp256k1_ecmult_context_t *ctx, secp256k1_ge_t *key, const secp256k1_scalar_t *tweak); static int secp256k1_eckey_privkey_tweak_mul(secp256k1_scalar_t *key, const secp256k1_scalar_t *tweak); -static int secp256k1_eckey_pubkey_tweak_mul(secp256k1_ge_t *key, const secp256k1_scalar_t *tweak); +static int secp256k1_eckey_pubkey_tweak_mul(const secp256k1_ecmult_context_t *ctx, secp256k1_ge_t *key, const secp256k1_scalar_t *tweak); #endif diff --git a/src/eckey_impl.h b/src/eckey_impl.h index 3e06d05b4..a332bd34e 100644 --- a/src/eckey_impl.h +++ b/src/eckey_impl.h @@ -24,8 +24,9 @@ static int secp256k1_eckey_pubkey_parse(secp256k1_ge_t *elem, const unsigned cha return 0; } secp256k1_ge_set_xy(elem, &x, &y); - if ((pub[0] == 0x06 || pub[0] == 0x07) && secp256k1_fe_is_odd(&y) != (pub[0] == 0x07)) + if ((pub[0] == 0x06 || pub[0] == 0x07) && secp256k1_fe_is_odd(&y) != (pub[0] == 0x07)) { return 0; + } return secp256k1_ge_is_valid_var(elem); } else { return 0; @@ -57,40 +58,47 @@ static int secp256k1_eckey_privkey_parse(secp256k1_scalar_t *key, const unsigned int len = 0; int overflow = 0; /* sequence header */ - if (end < privkey+1 || *privkey != 0x30) + if (end < privkey+1 || *privkey != 0x30) { return 0; + } privkey++; /* sequence length constructor */ - if (end < privkey+1 || !(*privkey & 0x80)) + if (end < privkey+1 || !(*privkey & 0x80)) { return 0; + } lenb = *privkey & ~0x80; privkey++; - if (lenb < 1 || lenb > 2) + if (lenb < 1 || lenb > 2) { return 0; - if (end < privkey+lenb) + } + if (end < privkey+lenb) { return 0; + } /* sequence length */ len = privkey[lenb-1] | (lenb > 1 ? privkey[lenb-2] << 8 : 0); privkey += lenb; - if (end < privkey+len) + if (end < privkey+len) { return 0; + } /* sequence element 0: version number (=1) */ - if (end < privkey+3 || privkey[0] != 0x02 || privkey[1] != 0x01 || privkey[2] != 0x01) + if (end < privkey+3 || privkey[0] != 0x02 || privkey[1] != 0x01 || privkey[2] != 0x01) { return 0; + } privkey += 3; /* sequence element 1: octet string, up to 32 bytes */ - if (end < privkey+2 || privkey[0] != 0x04 || privkey[1] > 0x20 || end < privkey+2+privkey[1]) + if (end < privkey+2 || privkey[0] != 0x04 || privkey[1] > 0x20 || end < privkey+2+privkey[1]) { return 0; + } memcpy(c + 32 - privkey[1], privkey + 2, privkey[1]); secp256k1_scalar_set_b32(key, c, &overflow); memset(c, 0, 32); return !overflow; } -static int secp256k1_eckey_privkey_serialize(unsigned char *privkey, int *privkeylen, const secp256k1_scalar_t *key, int compressed) { +static int secp256k1_eckey_privkey_serialize(const secp256k1_ecmult_gen_context_t *ctx, unsigned char *privkey, int *privkeylen, const secp256k1_scalar_t *key, int compressed) { secp256k1_gej_t rp; secp256k1_ge_t r; int pubkeylen = 0; - secp256k1_ecmult_gen(&rp, key); + secp256k1_ecmult_gen(ctx, &rp, key); secp256k1_ge_set_gej(&r, &rp); if (compressed) { static const unsigned char begin[] = { @@ -148,41 +156,45 @@ static int secp256k1_eckey_privkey_serialize(unsigned char *privkey, int *privke static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar_t *key, const secp256k1_scalar_t *tweak) { secp256k1_scalar_add(key, key, tweak); - if (secp256k1_scalar_is_zero(key)) + if (secp256k1_scalar_is_zero(key)) { return 0; + } return 1; } -static int secp256k1_eckey_pubkey_tweak_add(secp256k1_ge_t *key, const secp256k1_scalar_t *tweak) { +static int secp256k1_eckey_pubkey_tweak_add(const secp256k1_ecmult_context_t *ctx, secp256k1_ge_t *key, const secp256k1_scalar_t *tweak) { secp256k1_gej_t pt; secp256k1_scalar_t one; secp256k1_gej_set_ge(&pt, key); secp256k1_scalar_set_int(&one, 1); - secp256k1_ecmult(&pt, &pt, &one, tweak); + secp256k1_ecmult(ctx, &pt, &pt, &one, tweak); - if (secp256k1_gej_is_infinity(&pt)) + if (secp256k1_gej_is_infinity(&pt)) { return 0; + } secp256k1_ge_set_gej(key, &pt); return 1; } static int secp256k1_eckey_privkey_tweak_mul(secp256k1_scalar_t *key, const secp256k1_scalar_t *tweak) { - if (secp256k1_scalar_is_zero(tweak)) + if (secp256k1_scalar_is_zero(tweak)) { return 0; + } secp256k1_scalar_mul(key, key, tweak); return 1; } -static int secp256k1_eckey_pubkey_tweak_mul(secp256k1_ge_t *key, const secp256k1_scalar_t *tweak) { +static int secp256k1_eckey_pubkey_tweak_mul(const secp256k1_ecmult_context_t *ctx, secp256k1_ge_t *key, const secp256k1_scalar_t *tweak) { secp256k1_scalar_t zero; secp256k1_gej_t pt; - if (secp256k1_scalar_is_zero(tweak)) + if (secp256k1_scalar_is_zero(tweak)) { return 0; + } secp256k1_scalar_set_int(&zero, 0); secp256k1_gej_set_ge(&pt, key); - secp256k1_ecmult(&pt, &pt, tweak, &zero); + secp256k1_ecmult(ctx, &pt, &pt, tweak, &zero); secp256k1_ge_set_gej(key, &pt); return 1; } diff --git a/src/ecmult.h b/src/ecmult.h index 15a7100a4..bab9e4ef5 100644 --- a/src/ecmult.h +++ b/src/ecmult.h @@ -10,10 +10,22 @@ #include "num.h" #include "group.h" -static void secp256k1_ecmult_start(void); -static void secp256k1_ecmult_stop(void); +typedef struct { + /* For accelerating the computation of a*P + b*G: */ + secp256k1_ge_storage_t (*pre_g)[]; /* odd multiples of the generator */ +#ifdef USE_ENDOMORPHISM + secp256k1_ge_storage_t (*pre_g_128)[]; /* odd multiples of 2^128*generator */ +#endif +} secp256k1_ecmult_context_t; + +static void secp256k1_ecmult_context_init(secp256k1_ecmult_context_t *ctx); +static void secp256k1_ecmult_context_build(secp256k1_ecmult_context_t *ctx); +static void secp256k1_ecmult_context_clone(secp256k1_ecmult_context_t *dst, + const secp256k1_ecmult_context_t *src); +static void secp256k1_ecmult_context_clear(secp256k1_ecmult_context_t *ctx); +static int secp256k1_ecmult_context_is_built(const secp256k1_ecmult_context_t *ctx); /** Double multiply: R = na*A + ng*G */ -static void secp256k1_ecmult(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_scalar_t *na, const secp256k1_scalar_t *ng); +static void secp256k1_ecmult(const secp256k1_ecmult_context_t *ctx, secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_scalar_t *na, const secp256k1_scalar_t *ng); #endif diff --git a/src/ecmult_gen.h b/src/ecmult_gen.h index 42f822f9c..3745633c4 100644 --- a/src/ecmult_gen.h +++ b/src/ecmult_gen.h @@ -10,10 +10,34 @@ #include "scalar.h" #include "group.h" -static void secp256k1_ecmult_gen_start(void); -static void secp256k1_ecmult_gen_stop(void); +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. + * * Compute sum(n_i * 16^i * G + U_i, i=0..63), where: + * * U_i = U * 2^i (for i=0..62) + * * U_i = U * (1-2^63) (for i=63) + * where U is a point with no known corresponding scalar. Note that sum(U_i, i=0..63) = 0. + * For each i, and each of the 16 possible values of n_i, (n_i * 16^i * G + U_i) is + * precomputed (call it prec(i, n_i)). The formula now becomes sum(prec(i, n_i), i=0..63). + * None of the resulting prec group elements have a known scalar, and neither do any of + * the intermediate sums while computing a*G. + */ + secp256k1_ge_storage_t (*prec)[64][16]; /* prec[j][i] = 16^j * i * G + U_i */ + secp256k1_scalar_t blind; + secp256k1_gej_t initial; +} secp256k1_ecmult_gen_context_t; + +static void secp256k1_ecmult_gen_context_init(secp256k1_ecmult_gen_context_t* ctx); +static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context_t* ctx); +static void secp256k1_ecmult_gen_context_clone(secp256k1_ecmult_gen_context_t *dst, + const secp256k1_ecmult_gen_context_t* src); +static void secp256k1_ecmult_gen_context_clear(secp256k1_ecmult_gen_context_t* ctx); +static int secp256k1_ecmult_gen_context_is_built(const secp256k1_ecmult_gen_context_t* ctx); /** Multiply with the generator: R = a*G */ -static void secp256k1_ecmult_gen(secp256k1_gej_t *r, const secp256k1_scalar_t *a); +static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context_t* ctx, secp256k1_gej_t *r, const secp256k1_scalar_t *a); + +static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context_t *ctx, const unsigned char *seed32); #endif diff --git a/src/ecmult_gen_impl.h b/src/ecmult_gen_impl.h index 849452c7a..4697753ac 100644 --- a/src/ecmult_gen_impl.h +++ b/src/ecmult_gen_impl.h @@ -1,5 +1,5 @@ /********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * + * Copyright (c) 2013, 2014, 2015 Pieter Wuille, Gregory Maxwell * * Distributed under the MIT software license, see the accompanying * * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ @@ -10,36 +10,23 @@ #include "scalar.h" #include "group.h" #include "ecmult_gen.h" +#include "hash_impl.h" -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. - * * Compute sum(n_i * 16^i * G + U_i, i=0..63), where: - * * U_i = U * 2^i (for i=0..62) - * * U_i = U * (1-2^63) (for i=63) - * where U is a point with no known corresponding scalar. Note that sum(U_i, i=0..63) = 0. - * For each i, and each of the 16 possible values of n_i, (n_i * 16^i * G + U_i) is - * precomputed (call it prec(i, n_i)). The formula now becomes sum(prec(i, n_i), i=0..63). - * None of the resulting prec group elements have a known scalar, and neither do any of - * the intermediate sums while computing a*G. - */ - secp256k1_ge_storage_t prec[64][16]; /* prec[j][i] = 16^j * i * G + U_i */ -} secp256k1_ecmult_gen_consts_t; +static void secp256k1_ecmult_gen_context_init(secp256k1_ecmult_gen_context_t *ctx) { + ctx->prec = NULL; +} -static const secp256k1_ecmult_gen_consts_t *secp256k1_ecmult_gen_consts = NULL; - -static void secp256k1_ecmult_gen_start(void) { +static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context_t *ctx) { secp256k1_ge_t prec[1024]; secp256k1_gej_t gj; secp256k1_gej_t nums_gej; - secp256k1_ecmult_gen_consts_t *ret; int i, j; - if (secp256k1_ecmult_gen_consts != NULL) - return; - /* Allocate the precomputation table. */ - ret = (secp256k1_ecmult_gen_consts_t*)checked_malloc(sizeof(secp256k1_ecmult_gen_consts_t)); + if (ctx->prec != NULL) { + return; + } + + ctx->prec = (secp256k1_ge_storage_t (*)[64][16])checked_malloc(sizeof(*ctx->prec)); /* get the generator */ secp256k1_gej_set_ge(&gj, &secp256k1_ge_const_g); @@ -85,42 +72,113 @@ static void secp256k1_ecmult_gen_start(void) { } for (j = 0; j < 64; j++) { for (i = 0; i < 16; i++) { - secp256k1_ge_to_storage(&ret->prec[j][i], &prec[j*16 + i]); + secp256k1_ge_to_storage(&(*ctx->prec)[j][i], &prec[j*16 + i]); } } - - /* Set the global pointer to the precomputation table. */ - secp256k1_ecmult_gen_consts = ret; + secp256k1_ecmult_gen_blind(ctx, NULL); } -static void secp256k1_ecmult_gen_stop(void) { - secp256k1_ecmult_gen_consts_t *c; - if (secp256k1_ecmult_gen_consts == NULL) - return; - - c = (secp256k1_ecmult_gen_consts_t*)secp256k1_ecmult_gen_consts; - secp256k1_ecmult_gen_consts = NULL; - free(c); +static int secp256k1_ecmult_gen_context_is_built(const secp256k1_ecmult_gen_context_t* ctx) { + return ctx->prec != NULL; } -static void secp256k1_ecmult_gen(secp256k1_gej_t *r, const secp256k1_scalar_t *gn) { - const secp256k1_ecmult_gen_consts_t *c = secp256k1_ecmult_gen_consts; +static void secp256k1_ecmult_gen_context_clone(secp256k1_ecmult_gen_context_t *dst, + const secp256k1_ecmult_gen_context_t *src) { + if (src->prec == NULL) { + dst->prec = NULL; + } else { + dst->prec = (secp256k1_ge_storage_t (*)[64][16])checked_malloc(sizeof(*dst->prec)); + memcpy(dst->prec, src->prec, sizeof(*dst->prec)); + dst->initial = src->initial; + dst->blind = src->blind; + } +} + +static void secp256k1_ecmult_gen_context_clear(secp256k1_ecmult_gen_context_t *ctx) { + free(ctx->prec); + secp256k1_scalar_clear(&ctx->blind); + secp256k1_gej_clear(&ctx->initial); + ctx->prec = NULL; +} + +static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context_t *ctx, secp256k1_gej_t *r, const secp256k1_scalar_t *gn) { secp256k1_ge_t add; secp256k1_ge_storage_t adds; + secp256k1_scalar_t gnb; int bits; int i, j; - secp256k1_gej_set_infinity(r); + memset(&adds, 0, sizeof(adds)); + *r = ctx->initial; + /* Blind scalar/point multiplication by computing (n-b)G + bG instead of nG. */ + secp256k1_scalar_add(&gnb, gn, &ctx->blind); add.infinity = 0; for (j = 0; j < 64; j++) { - bits = secp256k1_scalar_get_bits(gn, j * 4, 4); + bits = secp256k1_scalar_get_bits(&gnb, j * 4, 4); for (i = 0; i < 16; i++) { - secp256k1_ge_storage_cmov(&adds, &c->prec[j][i], i == bits); + /** This uses a conditional move to avoid any secret data in array indexes. + * _Any_ use of secret indexes has been demonstrated to result in timing + * sidechannels, even when the cache-line access patterns are uniform. + * See also: + * "A word of warning", CHES 2013 Rump Session, by Daniel J. Bernstein and Peter Schwabe + * (https://cryptojedi.org/peter/data/chesrump-20130822.pdf) and + * "Cache Attacks and Countermeasures: the Case of AES", RSA 2006, + * by Dag Arne Osvik, Adi Shamir, and Eran Tromer + * (http://www.tau.ac.il/~tromer/papers/cache.pdf) + */ + secp256k1_ge_storage_cmov(&adds, &(*ctx->prec)[j][i], i == bits); } secp256k1_ge_from_storage(&add, &adds); secp256k1_gej_add_ge(r, r, &add); } bits = 0; secp256k1_ge_clear(&add); + secp256k1_scalar_clear(&gnb); +} + +/* Setup blinding values for secp256k1_ecmult_gen. */ +static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context_t *ctx, const unsigned char *seed32) { + secp256k1_scalar_t b; + secp256k1_gej_t gb; + secp256k1_fe_t s; + unsigned char nonce32[32]; + secp256k1_rfc6979_hmac_sha256_t rng; + int retry; + if (!seed32) { + /* When seed is NULL, reset the initial point and blinding value. */ + secp256k1_gej_set_ge(&ctx->initial, &secp256k1_ge_const_g); + secp256k1_gej_neg(&ctx->initial, &ctx->initial); + secp256k1_scalar_set_int(&ctx->blind, 1); + } + /* The prior blinding value (if not reset) is chained forward by including it in the hash. */ + secp256k1_scalar_get_b32(nonce32, &ctx->blind); + /** Using a CSPRNG allows a failure free interface, avoids needing large amounts of random data, + * and guards against weak or adversarial seeds. This is a simpler and safer interface than + * asking the caller for blinding values directly and expecting them to retry on failure. + */ + secp256k1_rfc6979_hmac_sha256_initialize(&rng, seed32 ? seed32 : nonce32, 32, nonce32, 32, NULL, 0); + /* Retry for out of range results to achieve uniformity. */ + do { + secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32); + retry = !secp256k1_fe_set_b32(&s, nonce32); + retry |= secp256k1_fe_is_zero(&s); + } while (retry); + /* Randomize the projection to defend against multiplier sidechannels. */ + secp256k1_gej_rescale(&ctx->initial, &s); + secp256k1_fe_clear(&s); + do { + secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32); + secp256k1_scalar_set_b32(&b, nonce32, &retry); + /* A blinding value of 0 works, but would undermine the projection hardening. */ + retry |= secp256k1_scalar_is_zero(&b); + } while (retry); + secp256k1_rfc6979_hmac_sha256_finalize(&rng); + memset(nonce32, 0, 32); + secp256k1_ecmult_gen(ctx, &gb, &b); + secp256k1_scalar_negate(&b, &b); + ctx->blind = b; + ctx->initial = gb; + secp256k1_scalar_clear(&b); + secp256k1_gej_clear(&gb); } #endif diff --git a/src/ecmult_impl.h b/src/ecmult_impl.h index ece0b0a45..1b2856f83 100644 --- a/src/ecmult_impl.h +++ b/src/ecmult_impl.h @@ -41,16 +41,17 @@ static void secp256k1_ecmult_table_precomp_gej_var(secp256k1_gej_t *pre, const s int i; pre[0] = *a; secp256k1_gej_double_var(&d, &pre[0]); - for (i = 1; i < (1 << (w-2)); i++) + for (i = 1; i < (1 << (w-2)); i++) { secp256k1_gej_add_var(&pre[i], &d, &pre[i-1]); + } } static void secp256k1_ecmult_table_precomp_ge_storage_var(secp256k1_ge_storage_t *pre, const secp256k1_gej_t *a, int w) { secp256k1_gej_t d; int i; const int table_size = 1 << (w-2); - secp256k1_gej_t *prej = checked_malloc(sizeof(secp256k1_gej_t) * table_size); - secp256k1_ge_t *prea = checked_malloc(sizeof(secp256k1_ge_t) * table_size); + secp256k1_gej_t *prej = (secp256k1_gej_t *)checked_malloc(sizeof(secp256k1_gej_t) * table_size); + secp256k1_ge_t *prea = (secp256k1_ge_t *)checked_malloc(sizeof(secp256k1_ge_t) * table_size); prej[0] = *a; secp256k1_gej_double_var(&d, a); for (i = 1; i < table_size; i++) { @@ -73,73 +74,93 @@ static void secp256k1_ecmult_table_precomp_ge_storage_var(secp256k1_ge_storage_t VERIFY_CHECK(((n) & 1) == 1); \ VERIFY_CHECK((n) >= -((1 << ((w)-1)) - 1)); \ VERIFY_CHECK((n) <= ((1 << ((w)-1)) - 1)); \ - if ((n) > 0) \ + if ((n) > 0) { \ *(r) = (pre)[((n)-1)/2]; \ - else \ + } else { \ secp256k1_gej_neg((r), &(pre)[(-(n)-1)/2]); \ + } \ } while(0) #define ECMULT_TABLE_GET_GE_STORAGE(r,pre,n,w) do { \ VERIFY_CHECK(((n) & 1) == 1); \ VERIFY_CHECK((n) >= -((1 << ((w)-1)) - 1)); \ VERIFY_CHECK((n) <= ((1 << ((w)-1)) - 1)); \ - if ((n) > 0) \ + if ((n) > 0) { \ secp256k1_ge_from_storage((r), &(pre)[((n)-1)/2]); \ - else {\ + } else { \ secp256k1_ge_from_storage((r), &(pre)[(-(n)-1)/2]); \ secp256k1_ge_neg((r), (r)); \ } \ } while(0) -typedef struct { - /* For accelerating the computation of a*P + b*G: */ - secp256k1_ge_storage_t pre_g[ECMULT_TABLE_SIZE(WINDOW_G)]; /* odd multiples of the generator */ +static void secp256k1_ecmult_context_init(secp256k1_ecmult_context_t *ctx) { + ctx->pre_g = NULL; #ifdef USE_ENDOMORPHISM - secp256k1_ge_storage_t pre_g_128[ECMULT_TABLE_SIZE(WINDOW_G)]; /* odd multiples of 2^128*generator */ + ctx->pre_g_128 = NULL; #endif -} secp256k1_ecmult_consts_t; +} -static const secp256k1_ecmult_consts_t *secp256k1_ecmult_consts = NULL; - -static void secp256k1_ecmult_start(void) { +static void secp256k1_ecmult_context_build(secp256k1_ecmult_context_t *ctx) { secp256k1_gej_t gj; - secp256k1_ecmult_consts_t *ret; - if (secp256k1_ecmult_consts != NULL) - return; - /* Allocate the precomputation table. */ - ret = (secp256k1_ecmult_consts_t*)checked_malloc(sizeof(secp256k1_ecmult_consts_t)); + if (ctx->pre_g != NULL) { + return; + } /* get the generator */ secp256k1_gej_set_ge(&gj, &secp256k1_ge_const_g); + ctx->pre_g = (secp256k1_ge_storage_t (*)[])checked_malloc(sizeof((*ctx->pre_g)[0]) * ECMULT_TABLE_SIZE(WINDOW_G)); /* precompute the tables with odd multiples */ - secp256k1_ecmult_table_precomp_ge_storage_var(ret->pre_g, &gj, WINDOW_G); + secp256k1_ecmult_table_precomp_ge_storage_var(*ctx->pre_g, &gj, WINDOW_G); #ifdef USE_ENDOMORPHISM { secp256k1_gej_t g_128j; int i; + + ctx->pre_g_128 = (secp256k1_ge_storage_t (*)[])checked_malloc(sizeof((*ctx->pre_g_128)[0]) * ECMULT_TABLE_SIZE(WINDOW_G)); + /* calculate 2^128*generator */ g_128j = gj; - for (i = 0; i < 128; i++) + for (i = 0; i < 128; i++) { secp256k1_gej_double_var(&g_128j, &g_128j); - secp256k1_ecmult_table_precomp_ge_storage_var(ret->pre_g_128, &g_128j, WINDOW_G); + } + secp256k1_ecmult_table_precomp_ge_storage_var(*ctx->pre_g_128, &g_128j, WINDOW_G); } #endif - - /* Set the global pointer to the precomputation table. */ - secp256k1_ecmult_consts = ret; } -static void secp256k1_ecmult_stop(void) { - secp256k1_ecmult_consts_t *c; - if (secp256k1_ecmult_consts == NULL) - return; +static void secp256k1_ecmult_context_clone(secp256k1_ecmult_context_t *dst, + const secp256k1_ecmult_context_t *src) { + if (src->pre_g == NULL) { + dst->pre_g = NULL; + } else { + size_t size = sizeof((*dst->pre_g)[0]) * ECMULT_TABLE_SIZE(WINDOW_G); + dst->pre_g = (secp256k1_ge_storage_t (*)[])checked_malloc(size); + memcpy(dst->pre_g, src->pre_g, size); + } +#ifdef USE_ENDOMORPHISM + if (src->pre_g_128 == NULL) { + dst->pre_g_128 = NULL; + } else { + size_t size = sizeof((*dst->pre_g_128)[0]) * ECMULT_TABLE_SIZE(WINDOW_G); + dst->pre_g_128 = (secp256k1_ge_storage_t (*)[])checked_malloc(size); + memcpy(dst->pre_g_128, src->pre_g_128, size); + } +#endif +} - c = (secp256k1_ecmult_consts_t*)secp256k1_ecmult_consts; - secp256k1_ecmult_consts = NULL; - free(c); +static int secp256k1_ecmult_context_is_built(const secp256k1_ecmult_context_t *ctx) { + return ctx->pre_g != NULL; +} + +static void secp256k1_ecmult_context_clear(secp256k1_ecmult_context_t *ctx) { + free(ctx->pre_g); +#ifdef USE_ENDOMORPHISM + free(ctx->pre_g_128); +#endif + secp256k1_ecmult_context_init(ctx); } /** Convert a number to WNAF notation. The number becomes represented by sum(2^i * wnaf[i], i=0..bits), @@ -186,11 +207,10 @@ static int secp256k1_ecmult_wnaf(int *wnaf, const secp256k1_scalar_t *a, int w) return set_bits; } -static void secp256k1_ecmult(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_scalar_t *na, const secp256k1_scalar_t *ng) { +static void secp256k1_ecmult(const secp256k1_ecmult_context_t *ctx, secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_scalar_t *na, const secp256k1_scalar_t *ng) { secp256k1_gej_t tmpj; secp256k1_gej_t pre_a[ECMULT_TABLE_SIZE(WINDOW_A)]; secp256k1_ge_t tmpa; - const secp256k1_ecmult_consts_t *c = secp256k1_ecmult_consts; #ifdef USE_ENDOMORPHISM secp256k1_gej_t pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)]; secp256k1_scalar_t na_1, na_lam; @@ -223,7 +243,9 @@ static void secp256k1_ecmult(secp256k1_gej_t *r, const secp256k1_gej_t *a, const VERIFY_CHECK(bits_na_1 <= 130); VERIFY_CHECK(bits_na_lam <= 130); bits = bits_na_1; - if (bits_na_lam > bits) bits = bits_na_lam; + if (bits_na_lam > bits) { + bits = bits_na_lam; + } #else /* build wnaf representation for na. */ bits_na = secp256k1_ecmult_wnaf(wnaf_na, na, WINDOW_A); @@ -234,8 +256,9 @@ static void secp256k1_ecmult(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_ecmult_table_precomp_gej_var(pre_a, a, WINDOW_A); #ifdef USE_ENDOMORPHISM - for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) + for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) { secp256k1_gej_mul_lambda(&pre_a_lam[i], &pre_a[i]); + } /* split ng into ng_1 and ng_128 (where gn = gn_1 + gn_128*2^128, and gn_1 and gn_128 are ~128 bit) */ secp256k1_scalar_split_128(&ng_1, &ng_128, ng); @@ -243,11 +266,17 @@ static void secp256k1_ecmult(secp256k1_gej_t *r, const secp256k1_gej_t *a, const /* Build wnaf representation for ng_1 and ng_128 */ bits_ng_1 = secp256k1_ecmult_wnaf(wnaf_ng_1, &ng_1, WINDOW_G); bits_ng_128 = secp256k1_ecmult_wnaf(wnaf_ng_128, &ng_128, WINDOW_G); - if (bits_ng_1 > bits) bits = bits_ng_1; - if (bits_ng_128 > bits) bits = bits_ng_128; + if (bits_ng_1 > bits) { + bits = bits_ng_1; + } + if (bits_ng_128 > bits) { + bits = bits_ng_128; + } #else bits_ng = secp256k1_ecmult_wnaf(wnaf_ng, ng, WINDOW_G); - if (bits_ng > bits) bits = bits_ng; + if (bits_ng > bits) { + bits = bits_ng; + } #endif secp256k1_gej_set_infinity(r); @@ -265,11 +294,11 @@ static void secp256k1_ecmult(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_gej_add_var(r, r, &tmpj); } if (i < bits_ng_1 && (n = wnaf_ng_1[i])) { - ECMULT_TABLE_GET_GE_STORAGE(&tmpa, c->pre_g, n, WINDOW_G); + ECMULT_TABLE_GET_GE_STORAGE(&tmpa, *ctx->pre_g, n, WINDOW_G); secp256k1_gej_add_ge_var(r, r, &tmpa); } if (i < bits_ng_128 && (n = wnaf_ng_128[i])) { - ECMULT_TABLE_GET_GE_STORAGE(&tmpa, c->pre_g_128, n, WINDOW_G); + ECMULT_TABLE_GET_GE_STORAGE(&tmpa, *ctx->pre_g_128, n, WINDOW_G); secp256k1_gej_add_ge_var(r, r, &tmpa); } #else @@ -278,7 +307,7 @@ static void secp256k1_ecmult(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_gej_add_var(r, r, &tmpj); } if (i < bits_ng && (n = wnaf_ng[i])) { - ECMULT_TABLE_GET_GE_STORAGE(&tmpa, c->pre_g, n, WINDOW_G); + ECMULT_TABLE_GET_GE_STORAGE(&tmpa, *ctx->pre_g, n, WINDOW_G); secp256k1_gej_add_ge_var(r, r, &tmpa); } #endif diff --git a/src/field.h b/src/field.h index 9e6d7d3c0..41b280892 100644 --- a/src/field.h +++ b/src/field.h @@ -113,4 +113,7 @@ static void secp256k1_fe_from_storage(secp256k1_fe_t *r, const secp256k1_fe_stor /** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. */ static void secp256k1_fe_storage_cmov(secp256k1_fe_storage_t *r, const secp256k1_fe_storage_t *a, int flag); +/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. */ +static void secp256k1_fe_cmov(secp256k1_fe_t *r, const secp256k1_fe_t *a, int flag); + #endif diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h index 0afbb18a4..871b91f91 100644 --- a/src/field_10x26_impl.h +++ b/src/field_10x26_impl.h @@ -236,8 +236,9 @@ static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe_t *r) { z1 = z0 ^ 0x3D0UL; /* Fast return path should catch the majority of cases */ - if ((z0 != 0UL) & (z1 != 0x3FFFFFFUL)) + if ((z0 != 0UL) & (z1 != 0x3FFFFFFUL)) { return 0; + } t1 = r->n[1]; t2 = r->n[2]; @@ -315,8 +316,12 @@ static int secp256k1_fe_cmp_var(const secp256k1_fe_t *a, const secp256k1_fe_t *b secp256k1_fe_verify(b); #endif for (i = 9; i >= 0; i--) { - if (a->n[i] > b->n[i]) return 1; - if (a->n[i] < b->n[i]) return -1; + if (a->n[i] > b->n[i]) { + return 1; + } + if (a->n[i] < b->n[i]) { + return -1; + } } return 0; } @@ -1063,6 +1068,26 @@ static void secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *a) { #endif } +static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe_t *r, const secp256k1_fe_t *a, int flag) { + uint32_t mask0, mask1; + mask0 = flag + ~((uint32_t)0); + mask1 = ~mask0; + r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1); + r->n[1] = (r->n[1] & mask0) | (a->n[1] & mask1); + r->n[2] = (r->n[2] & mask0) | (a->n[2] & mask1); + r->n[3] = (r->n[3] & mask0) | (a->n[3] & mask1); + r->n[4] = (r->n[4] & mask0) | (a->n[4] & mask1); + r->n[5] = (r->n[5] & mask0) | (a->n[5] & mask1); + r->n[6] = (r->n[6] & mask0) | (a->n[6] & mask1); + r->n[7] = (r->n[7] & mask0) | (a->n[7] & mask1); + r->n[8] = (r->n[8] & mask0) | (a->n[8] & mask1); + r->n[9] = (r->n[9] & mask0) | (a->n[9] & mask1); +#ifdef VERIFY + r->magnitude = (r->magnitude & mask0) | (a->magnitude & mask1); + r->normalized = (r->normalized & mask0) | (a->normalized & mask1); +#endif +} + static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage_t *r, const secp256k1_fe_storage_t *a, int flag) { uint32_t mask0, mask1; mask0 = flag + ~((uint32_t)0); diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h index 2f9c8704a..bda4c3dfc 100644 --- a/src/field_5x52_impl.h +++ b/src/field_5x52_impl.h @@ -209,8 +209,9 @@ static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe_t *r) { z1 = z0 ^ 0x1000003D0ULL; /* Fast return path should catch the majority of cases */ - if ((z0 != 0ULL) & (z1 != 0xFFFFFFFFFFFFFULL)) + if ((z0 != 0ULL) & (z1 != 0xFFFFFFFFFFFFFULL)) { return 0; + } t1 = r->n[1]; t2 = r->n[2]; @@ -277,8 +278,12 @@ static int secp256k1_fe_cmp_var(const secp256k1_fe_t *a, const secp256k1_fe_t *b secp256k1_fe_verify(b); #endif for (i = 4; i >= 0; i--) { - if (a->n[i] > b->n[i]) return 1; - if (a->n[i] < b->n[i]) return -1; + if (a->n[i] > b->n[i]) { + return 1; + } + if (a->n[i] < b->n[i]) { + return -1; + } } return 0; } @@ -399,6 +404,21 @@ static void secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *a) { #endif } +static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe_t *r, const secp256k1_fe_t *a, int flag) { + uint64_t mask0, mask1; + mask0 = flag + ~((uint64_t)0); + mask1 = ~mask0; + r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1); + r->n[1] = (r->n[1] & mask0) | (a->n[1] & mask1); + r->n[2] = (r->n[2] & mask0) | (a->n[2] & mask1); + r->n[3] = (r->n[3] & mask0) | (a->n[3] & mask1); + r->n[4] = (r->n[4] & mask0) | (a->n[4] & mask1); +#ifdef VERIFY + r->magnitude = (r->magnitude & mask0) | (a->magnitude & mask1); + r->normalized = (r->normalized & mask0) | (a->normalized & mask1); +#endif +} + static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage_t *r, const secp256k1_fe_storage_t *a, int flag) { uint64_t mask0, mask1; mask0 = flag + ~((uint64_t)0); diff --git a/src/field_impl.h b/src/field_impl.h index 047914cf2..e6ec11e8f 100644 --- a/src/field_impl.h +++ b/src/field_impl.h @@ -44,47 +44,69 @@ static int secp256k1_fe_sqrt_var(secp256k1_fe_t *r, const secp256k1_fe_t *a) { secp256k1_fe_mul(&x3, &x3, a); x6 = x3; - for (j=0; j<3; j++) secp256k1_fe_sqr(&x6, &x6); + for (j=0; j<3; j++) { + secp256k1_fe_sqr(&x6, &x6); + } secp256k1_fe_mul(&x6, &x6, &x3); x9 = x6; - for (j=0; j<3; j++) secp256k1_fe_sqr(&x9, &x9); + for (j=0; j<3; j++) { + secp256k1_fe_sqr(&x9, &x9); + } secp256k1_fe_mul(&x9, &x9, &x3); x11 = x9; - for (j=0; j<2; j++) secp256k1_fe_sqr(&x11, &x11); + for (j=0; j<2; j++) { + secp256k1_fe_sqr(&x11, &x11); + } secp256k1_fe_mul(&x11, &x11, &x2); x22 = x11; - for (j=0; j<11; j++) secp256k1_fe_sqr(&x22, &x22); + for (j=0; j<11; j++) { + secp256k1_fe_sqr(&x22, &x22); + } secp256k1_fe_mul(&x22, &x22, &x11); x44 = x22; - for (j=0; j<22; j++) secp256k1_fe_sqr(&x44, &x44); + for (j=0; j<22; j++) { + secp256k1_fe_sqr(&x44, &x44); + } secp256k1_fe_mul(&x44, &x44, &x22); x88 = x44; - for (j=0; j<44; j++) secp256k1_fe_sqr(&x88, &x88); + for (j=0; j<44; j++) { + secp256k1_fe_sqr(&x88, &x88); + } secp256k1_fe_mul(&x88, &x88, &x44); x176 = x88; - for (j=0; j<88; j++) secp256k1_fe_sqr(&x176, &x176); + for (j=0; j<88; j++) { + secp256k1_fe_sqr(&x176, &x176); + } secp256k1_fe_mul(&x176, &x176, &x88); x220 = x176; - for (j=0; j<44; j++) secp256k1_fe_sqr(&x220, &x220); + for (j=0; j<44; j++) { + secp256k1_fe_sqr(&x220, &x220); + } secp256k1_fe_mul(&x220, &x220, &x44); x223 = x220; - for (j=0; j<3; j++) secp256k1_fe_sqr(&x223, &x223); + for (j=0; j<3; j++) { + secp256k1_fe_sqr(&x223, &x223); + } secp256k1_fe_mul(&x223, &x223, &x3); /* The final result is then assembled using a sliding window over the blocks. */ t1 = x223; - for (j=0; j<23; j++) secp256k1_fe_sqr(&t1, &t1); + for (j=0; j<23; j++) { + secp256k1_fe_sqr(&t1, &t1); + } secp256k1_fe_mul(&t1, &t1, &x22); - for (j=0; j<6; j++) secp256k1_fe_sqr(&t1, &t1); + for (j=0; j<6; j++) { + secp256k1_fe_sqr(&t1, &t1); + } secp256k1_fe_mul(&t1, &t1, &x2); secp256k1_fe_sqr(&t1, &t1); secp256k1_fe_sqr(r, &t1); @@ -111,51 +133,77 @@ static void secp256k1_fe_inv(secp256k1_fe_t *r, const secp256k1_fe_t *a) { secp256k1_fe_mul(&x3, &x3, a); x6 = x3; - for (j=0; j<3; j++) secp256k1_fe_sqr(&x6, &x6); + for (j=0; j<3; j++) { + secp256k1_fe_sqr(&x6, &x6); + } secp256k1_fe_mul(&x6, &x6, &x3); x9 = x6; - for (j=0; j<3; j++) secp256k1_fe_sqr(&x9, &x9); + for (j=0; j<3; j++) { + secp256k1_fe_sqr(&x9, &x9); + } secp256k1_fe_mul(&x9, &x9, &x3); x11 = x9; - for (j=0; j<2; j++) secp256k1_fe_sqr(&x11, &x11); + for (j=0; j<2; j++) { + secp256k1_fe_sqr(&x11, &x11); + } secp256k1_fe_mul(&x11, &x11, &x2); x22 = x11; - for (j=0; j<11; j++) secp256k1_fe_sqr(&x22, &x22); + for (j=0; j<11; j++) { + secp256k1_fe_sqr(&x22, &x22); + } secp256k1_fe_mul(&x22, &x22, &x11); x44 = x22; - for (j=0; j<22; j++) secp256k1_fe_sqr(&x44, &x44); + for (j=0; j<22; j++) { + secp256k1_fe_sqr(&x44, &x44); + } secp256k1_fe_mul(&x44, &x44, &x22); x88 = x44; - for (j=0; j<44; j++) secp256k1_fe_sqr(&x88, &x88); + for (j=0; j<44; j++) { + secp256k1_fe_sqr(&x88, &x88); + } secp256k1_fe_mul(&x88, &x88, &x44); x176 = x88; - for (j=0; j<88; j++) secp256k1_fe_sqr(&x176, &x176); + for (j=0; j<88; j++) { + secp256k1_fe_sqr(&x176, &x176); + } secp256k1_fe_mul(&x176, &x176, &x88); x220 = x176; - for (j=0; j<44; j++) secp256k1_fe_sqr(&x220, &x220); + for (j=0; j<44; j++) { + secp256k1_fe_sqr(&x220, &x220); + } secp256k1_fe_mul(&x220, &x220, &x44); x223 = x220; - for (j=0; j<3; j++) secp256k1_fe_sqr(&x223, &x223); + for (j=0; j<3; j++) { + secp256k1_fe_sqr(&x223, &x223); + } secp256k1_fe_mul(&x223, &x223, &x3); /* The final result is then assembled using a sliding window over the blocks. */ t1 = x223; - for (j=0; j<23; j++) secp256k1_fe_sqr(&t1, &t1); + for (j=0; j<23; j++) { + secp256k1_fe_sqr(&t1, &t1); + } secp256k1_fe_mul(&t1, &t1, &x22); - for (j=0; j<5; j++) secp256k1_fe_sqr(&t1, &t1); + for (j=0; j<5; j++) { + secp256k1_fe_sqr(&t1, &t1); + } secp256k1_fe_mul(&t1, &t1, a); - for (j=0; j<3; j++) secp256k1_fe_sqr(&t1, &t1); + for (j=0; j<3; j++) { + secp256k1_fe_sqr(&t1, &t1); + } secp256k1_fe_mul(&t1, &t1, &x2); - for (j=0; j<2; j++) secp256k1_fe_sqr(&t1, &t1); + for (j=0; j<2; j++) { + secp256k1_fe_sqr(&t1, &t1); + } secp256k1_fe_mul(r, a, &t1); } @@ -188,8 +236,9 @@ static void secp256k1_fe_inv_var(secp256k1_fe_t *r, const secp256k1_fe_t *a) { static void secp256k1_fe_inv_all_var(size_t len, secp256k1_fe_t *r, const secp256k1_fe_t *a) { secp256k1_fe_t u; size_t i; - if (len < 1) + if (len < 1) { return; + } VERIFY_CHECK((r + len <= a) || (a + len <= r)); diff --git a/src/group.h b/src/group.h index d1e583490..0b08b3b99 100644 --- a/src/group.h +++ b/src/group.h @@ -115,4 +115,7 @@ static void secp256k1_ge_from_storage(secp256k1_ge_t *r, const secp256k1_ge_stor /** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. */ static void secp256k1_ge_storage_cmov(secp256k1_ge_storage_t *r, const secp256k1_ge_storage_t *a, int flag); +/** Rescale a jacobian point by b which must be non-zero. Constant-time. */ +static void secp256k1_gej_rescale(secp256k1_gej_t *r, const secp256k1_fe_t *b); + #endif diff --git a/src/group_impl.h b/src/group_impl.h index 8d8c359c5..0f64576fb 100644 --- a/src/group_impl.h +++ b/src/group_impl.h @@ -77,14 +77,14 @@ static void secp256k1_ge_set_all_gej_var(size_t len, secp256k1_ge_t *r, const se secp256k1_fe_t *azi; size_t i; size_t count = 0; - az = checked_malloc(sizeof(secp256k1_fe_t) * len); + az = (secp256k1_fe_t *)checked_malloc(sizeof(secp256k1_fe_t) * len); for (i = 0; i < len; i++) { if (!a[i].infinity) { az[count++] = a[i].z; } } - azi = checked_malloc(sizeof(secp256k1_fe_t) * count); + azi = (secp256k1_fe_t *)checked_malloc(sizeof(secp256k1_fe_t) * count); secp256k1_fe_inv_all_var(count, azi, az); free(az); @@ -138,11 +138,13 @@ static int secp256k1_ge_set_xo_var(secp256k1_ge_t *r, const secp256k1_fe_t *x, i r->infinity = 0; secp256k1_fe_set_int(&c, 7); secp256k1_fe_add(&c, &x3); - if (!secp256k1_fe_sqrt_var(&r->y, &c)) + if (!secp256k1_fe_sqrt_var(&r->y, &c)) { return 0; + } secp256k1_fe_normalize_var(&r->y); - if (secp256k1_fe_is_odd(&r->y) != odd) + if (secp256k1_fe_is_odd(&r->y) != odd) { secp256k1_fe_negate(&r->y, &r->y, 1); + } return 1; } @@ -176,8 +178,9 @@ static int secp256k1_gej_is_infinity(const secp256k1_gej_t *a) { static int secp256k1_gej_is_valid_var(const secp256k1_gej_t *a) { secp256k1_fe_t y2, x3, z2, z6; - if (a->infinity) + if (a->infinity) { return 0; + } /** y^2 = x^3 + 7 * (Y/Z^3)^2 = (X/Z^2)^3 + 7 * Y^2 / Z^6 = X^3 / Z^6 + 7 @@ -195,8 +198,9 @@ static int secp256k1_gej_is_valid_var(const secp256k1_gej_t *a) { static int secp256k1_ge_is_valid_var(const secp256k1_ge_t *a) { secp256k1_fe_t y2, x3, c; - if (a->infinity) + if (a->infinity) { return 0; + } /* y^2 = x^3 + 7 */ secp256k1_fe_sqr(&y2, &a->y); secp256k1_fe_sqr(&x3, &a->x); secp256k1_fe_mul(&x3, &x3, &a->x); @@ -321,7 +325,8 @@ static void secp256k1_gej_add_ge_var(secp256k1_gej_t *r, const secp256k1_gej_t * } static void secp256k1_gej_add_ge(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_ge_t *b) { - /* Operations: 7 mul, 5 sqr, 5 normalize, 19 mul_int/add/negate */ + /* Operations: 7 mul, 5 sqr, 5 normalize, 17 mul_int/add/negate/cmov */ + static const secp256k1_fe_t fe_1 = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1); secp256k1_fe_t zz, u1, u2, s1, s2, z, t, m, n, q, rr; int infinity; VERIFY_CHECK(!b->infinity); @@ -383,17 +388,25 @@ static void secp256k1_gej_add_ge(secp256k1_gej_t *r, const secp256k1_gej_t *a, c secp256k1_fe_mul_int(&r->y, 4 * (1 - a->infinity)); /* r->y = Y3 = 4*R*(3*Q-2*R^2)-4*M^4 (4) */ /** In case a->infinity == 1, the above code results in r->x, r->y, and r->z all equal to 0. - * Add b->x to x, b->y to y, and 1 to z in that case. + * Replace r with b->x, b->y, 1 in that case. */ - t = b->x; secp256k1_fe_mul_int(&t, a->infinity); - secp256k1_fe_add(&r->x, &t); - t = b->y; secp256k1_fe_mul_int(&t, a->infinity); - secp256k1_fe_add(&r->y, &t); - secp256k1_fe_set_int(&t, a->infinity); - secp256k1_fe_add(&r->z, &t); + secp256k1_fe_cmov(&r->x, &b->x, a->infinity); + secp256k1_fe_cmov(&r->y, &b->y, a->infinity); + secp256k1_fe_cmov(&r->z, &fe_1, a->infinity); r->infinity = infinity; } +static void secp256k1_gej_rescale(secp256k1_gej_t *r, const secp256k1_fe_t *s) { + /* Operations: 4 mul, 1 sqr */ + secp256k1_fe_t zz; + VERIFY_CHECK(!secp256k1_fe_is_zero(s)); + secp256k1_fe_sqr(&zz, s); + secp256k1_fe_mul(&r->x, &r->x, &zz); /* r->x *= s^2 */ + secp256k1_fe_mul(&r->y, &r->y, &zz); + secp256k1_fe_mul(&r->y, &r->y, s); /* r->y *= s^3 */ + secp256k1_fe_mul(&r->z, &r->z, s); /* r->z *= s */ +} + static void secp256k1_ge_to_storage(secp256k1_ge_storage_t *r, const secp256k1_ge_t *a) { secp256k1_fe_t x, y; VERIFY_CHECK(!a->infinity); diff --git a/src/hash_impl.h b/src/hash_impl.h index 60fdbf771..9828827bc 100644 --- a/src/hash_impl.h +++ b/src/hash_impl.h @@ -176,13 +176,15 @@ static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256_t *hash, cons } secp256k1_sha256_initialize(&hash->outer); - for (n = 0; n < 64; n++) + for (n = 0; n < 64; n++) { rkey[n] ^= 0x5c; + } secp256k1_sha256_write(&hash->outer, rkey, 64); secp256k1_sha256_initialize(&hash->inner); - for (n = 0; n < 64; n++) + for (n = 0; n < 64; n++) { rkey[n] ^= 0x5c ^ 0x36; + } secp256k1_sha256_write(&hash->inner, rkey, 64); memset(rkey, 0, 64); } @@ -205,15 +207,17 @@ static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha2 static const unsigned char zero[1] = {0x00}; static const unsigned char one[1] = {0x01}; - memset(rng->v, 0x01, 32); - memset(rng->k, 0x00, 32); + memset(rng->v, 0x01, 32); /* RFC6979 3.2.b. */ + memset(rng->k, 0x00, 32); /* RFC6979 3.2.c. */ + /* RFC6979 3.2.d. */ secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); secp256k1_hmac_sha256_write(&hmac, rng->v, 32); secp256k1_hmac_sha256_write(&hmac, zero, 1); secp256k1_hmac_sha256_write(&hmac, key, keylen); secp256k1_hmac_sha256_write(&hmac, msg, msglen); if (rnd && rndlen) { + /* RFC6979 3.6 "Additional data". */ secp256k1_hmac_sha256_write(&hmac, rnd, rndlen); } secp256k1_hmac_sha256_finalize(&hmac, rng->k); @@ -221,12 +225,14 @@ static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha2 secp256k1_hmac_sha256_write(&hmac, rng->v, 32); secp256k1_hmac_sha256_finalize(&hmac, rng->v); + /* RFC6979 3.2.f. */ secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); secp256k1_hmac_sha256_write(&hmac, rng->v, 32); secp256k1_hmac_sha256_write(&hmac, one, 1); secp256k1_hmac_sha256_write(&hmac, key, keylen); secp256k1_hmac_sha256_write(&hmac, msg, msglen); if (rnd && rndlen) { + /* RFC6979 3.6 "Additional data". */ secp256k1_hmac_sha256_write(&hmac, rnd, rndlen); } secp256k1_hmac_sha256_finalize(&hmac, rng->k); @@ -237,6 +243,7 @@ static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha2 } static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256_t *rng, unsigned char *out, size_t outlen) { + /* RFC6979 3.2.h. */ static const unsigned char zero[1] = {0x00}; if (rng->retry) { secp256k1_hmac_sha256_t hmac; diff --git a/src/num_gmp_impl.h b/src/num_gmp_impl.h index 3e4b92d32..dbbc458d5 100644 --- a/src/num_gmp_impl.h +++ b/src/num_gmp_impl.h @@ -54,7 +54,9 @@ static void secp256k1_num_set_bin(secp256k1_num_t *r, const unsigned char *a, un VERIFY_CHECK(len <= NUM_LIMBS*2); r->limbs = len; r->neg = 0; - while (r->limbs > 1 && r->data[r->limbs-1]==0) r->limbs--; + while (r->limbs > 1 && r->data[r->limbs-1]==0) { + r->limbs--; + } } static void secp256k1_num_add_abs(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) { @@ -70,7 +72,9 @@ static void secp256k1_num_sub_abs(secp256k1_num_t *r, const secp256k1_num_t *a, mp_limb_t c = mpn_sub(r->data, a->data, a->limbs, b->data, b->limbs); VERIFY_CHECK(c == 0); r->limbs = a->limbs; - while (r->limbs > 1 && r->data[r->limbs-1]==0) r->limbs--; + while (r->limbs > 1 && r->data[r->limbs-1]==0) { + r->limbs--; + } } static void secp256k1_num_mod(secp256k1_num_t *r, const secp256k1_num_t *m) { @@ -82,7 +86,9 @@ static void secp256k1_num_mod(secp256k1_num_t *r, const secp256k1_num_t *m) { mpn_tdiv_qr(t, r->data, 0, r->data, r->limbs, m->data, m->limbs); memset(t, 0, sizeof(t)); r->limbs = m->limbs; - while (r->limbs > 1 && r->data[r->limbs-1]==0) r->limbs--; + while (r->limbs > 1 && r->data[r->limbs-1]==0) { + r->limbs--; + } } if (r->neg && (r->limbs > 1 || r->data[0] != 0)) { @@ -125,7 +131,9 @@ static void secp256k1_num_mod_inverse(secp256k1_num_t *r, const secp256k1_num_t if (sn < 0) { mpn_sub(r->data, m->data, m->limbs, r->data, -sn); r->limbs = m->limbs; - while (r->limbs > 1 && r->data[r->limbs-1]==0) r->limbs--; + while (r->limbs > 1 && r->data[r->limbs-1]==0) { + r->limbs--; + } } else { r->limbs = sn; } @@ -143,15 +151,25 @@ static int secp256k1_num_is_neg(const secp256k1_num_t *a) { } static int secp256k1_num_cmp(const secp256k1_num_t *a, const secp256k1_num_t *b) { - if (a->limbs > b->limbs) return 1; - if (a->limbs < b->limbs) return -1; + if (a->limbs > b->limbs) { + return 1; + } + if (a->limbs < b->limbs) { + return -1; + } return mpn_cmp(a->data, b->data, a->limbs); } static int secp256k1_num_eq(const secp256k1_num_t *a, const secp256k1_num_t *b) { - if (a->limbs > b->limbs) return 0; - if (a->limbs < b->limbs) return 0; - if ((a->neg && !secp256k1_num_is_zero(a)) != (b->neg && !secp256k1_num_is_zero(b))) return 0; + if (a->limbs > b->limbs) { + return 0; + } + if (a->limbs < b->limbs) { + return 0; + } + if ((a->neg && !secp256k1_num_is_zero(a)) != (b->neg && !secp256k1_num_is_zero(b))) { + return 0; + } return mpn_cmp(a->data, b->data, a->limbs) == 0; } @@ -198,12 +216,15 @@ static void secp256k1_num_mul(secp256k1_num_t *r, const secp256k1_num_t *a, cons r->data[0] = 0; return; } - if (a->limbs >= b->limbs) + if (a->limbs >= b->limbs) { mpn_mul(tmp, a->data, a->limbs, b->data, b->limbs); - else + } else { mpn_mul(tmp, b->data, b->limbs, a->data, a->limbs); + } r->limbs = a->limbs + b->limbs; - if (r->limbs > 1 && tmp[r->limbs - 1]==0) r->limbs--; + if (r->limbs > 1 && tmp[r->limbs - 1]==0) { + r->limbs--; + } VERIFY_CHECK(r->limbs <= 2*NUM_LIMBS); mpn_copyi(r->data, tmp, r->limbs); r->neg = a->neg ^ b->neg; @@ -227,7 +248,9 @@ static void secp256k1_num_shift(secp256k1_num_t *r, int bits) { } } } - while (r->limbs>1 && r->data[r->limbs-1]==0) r->limbs--; + while (r->limbs>1 && r->data[r->limbs-1]==0) { + r->limbs--; + } } static void secp256k1_num_negate(secp256k1_num_t *r) { diff --git a/src/scalar_impl.h b/src/scalar_impl.h index 3acbe264a..33824983e 100644 --- a/src/scalar_impl.h +++ b/src/scalar_impl.h @@ -69,130 +69,168 @@ static void secp256k1_scalar_inverse(secp256k1_scalar_t *r, const secp256k1_scal secp256k1_scalar_mul(&x8, &x8, x); secp256k1_scalar_sqr(&x15, &x8); - for (i = 0; i < 6; i++) + for (i = 0; i < 6; i++) { secp256k1_scalar_sqr(&x15, &x15); + } secp256k1_scalar_mul(&x15, &x15, &x7); secp256k1_scalar_sqr(&x30, &x15); - for (i = 0; i < 14; i++) + for (i = 0; i < 14; i++) { secp256k1_scalar_sqr(&x30, &x30); + } secp256k1_scalar_mul(&x30, &x30, &x15); secp256k1_scalar_sqr(&x60, &x30); - for (i = 0; i < 29; i++) + for (i = 0; i < 29; i++) { secp256k1_scalar_sqr(&x60, &x60); + } secp256k1_scalar_mul(&x60, &x60, &x30); secp256k1_scalar_sqr(&x120, &x60); - for (i = 0; i < 59; i++) + for (i = 0; i < 59; i++) { secp256k1_scalar_sqr(&x120, &x120); + } secp256k1_scalar_mul(&x120, &x120, &x60); secp256k1_scalar_sqr(&x127, &x120); - for (i = 0; i < 6; i++) + for (i = 0; i < 6; i++) { secp256k1_scalar_sqr(&x127, &x127); + } secp256k1_scalar_mul(&x127, &x127, &x7); /* Then accumulate the final result (t starts at x127). */ t = &x127; - for (i = 0; i < 2; i++) /* 0 */ + for (i = 0; i < 2; i++) { /* 0 */ secp256k1_scalar_sqr(t, t); + } secp256k1_scalar_mul(t, t, x); /* 1 */ - for (i = 0; i < 4; i++) /* 0 */ + for (i = 0; i < 4; i++) { /* 0 */ secp256k1_scalar_sqr(t, t); + } secp256k1_scalar_mul(t, t, &x3); /* 111 */ - for (i = 0; i < 2; i++) /* 0 */ + for (i = 0; i < 2; i++) { /* 0 */ secp256k1_scalar_sqr(t, t); + } secp256k1_scalar_mul(t, t, x); /* 1 */ - for (i = 0; i < 2; i++) /* 0 */ + for (i = 0; i < 2; i++) { /* 0 */ secp256k1_scalar_sqr(t, t); + } secp256k1_scalar_mul(t, t, x); /* 1 */ - for (i = 0; i < 2; i++) /* 0 */ + for (i = 0; i < 2; i++) { /* 0 */ secp256k1_scalar_sqr(t, t); + } secp256k1_scalar_mul(t, t, x); /* 1 */ - for (i = 0; i < 4; i++) /* 0 */ + for (i = 0; i < 4; i++) { /* 0 */ secp256k1_scalar_sqr(t, t); + } secp256k1_scalar_mul(t, t, &x3); /* 111 */ - for (i = 0; i < 3; i++) /* 0 */ + for (i = 0; i < 3; i++) { /* 0 */ secp256k1_scalar_sqr(t, t); + } secp256k1_scalar_mul(t, t, &x2); /* 11 */ - for (i = 0; i < 4; i++) /* 0 */ + for (i = 0; i < 4; i++) { /* 0 */ secp256k1_scalar_sqr(t, t); + } secp256k1_scalar_mul(t, t, &x3); /* 111 */ - for (i = 0; i < 5; i++) /* 00 */ + for (i = 0; i < 5; i++) { /* 00 */ secp256k1_scalar_sqr(t, t); + } secp256k1_scalar_mul(t, t, &x3); /* 111 */ - for (i = 0; i < 4; i++) /* 00 */ + for (i = 0; i < 4; i++) { /* 00 */ secp256k1_scalar_sqr(t, t); + } secp256k1_scalar_mul(t, t, &x2); /* 11 */ - for (i = 0; i < 2; i++) /* 0 */ + for (i = 0; i < 2; i++) { /* 0 */ secp256k1_scalar_sqr(t, t); + } secp256k1_scalar_mul(t, t, x); /* 1 */ - for (i = 0; i < 2; i++) /* 0 */ + for (i = 0; i < 2; i++) { /* 0 */ secp256k1_scalar_sqr(t, t); + } secp256k1_scalar_mul(t, t, x); /* 1 */ - for (i = 0; i < 5; i++) /* 0 */ + for (i = 0; i < 5; i++) { /* 0 */ secp256k1_scalar_sqr(t, t); + } secp256k1_scalar_mul(t, t, &x4); /* 1111 */ - for (i = 0; i < 2; i++) /* 0 */ + for (i = 0; i < 2; i++) { /* 0 */ secp256k1_scalar_sqr(t, t); + } secp256k1_scalar_mul(t, t, x); /* 1 */ - for (i = 0; i < 3; i++) /* 00 */ + for (i = 0; i < 3; i++) { /* 00 */ secp256k1_scalar_sqr(t, t); + } secp256k1_scalar_mul(t, t, x); /* 1 */ - for (i = 0; i < 4; i++) /* 000 */ + for (i = 0; i < 4; i++) { /* 000 */ secp256k1_scalar_sqr(t, t); + } secp256k1_scalar_mul(t, t, x); /* 1 */ - for (i = 0; i < 2; i++) /* 0 */ + for (i = 0; i < 2; i++) { /* 0 */ secp256k1_scalar_sqr(t, t); + } secp256k1_scalar_mul(t, t, x); /* 1 */ - for (i = 0; i < 10; i++) /* 0000000 */ + for (i = 0; i < 10; i++) { /* 0000000 */ secp256k1_scalar_sqr(t, t); + } secp256k1_scalar_mul(t, t, &x3); /* 111 */ - for (i = 0; i < 4; i++) /* 0 */ + for (i = 0; i < 4; i++) { /* 0 */ secp256k1_scalar_sqr(t, t); + } secp256k1_scalar_mul(t, t, &x3); /* 111 */ - for (i = 0; i < 9; i++) /* 0 */ + for (i = 0; i < 9; i++) { /* 0 */ secp256k1_scalar_sqr(t, t); + } secp256k1_scalar_mul(t, t, &x8); /* 11111111 */ - for (i = 0; i < 2; i++) /* 0 */ + for (i = 0; i < 2; i++) { /* 0 */ secp256k1_scalar_sqr(t, t); + } secp256k1_scalar_mul(t, t, x); /* 1 */ - for (i = 0; i < 3; i++) /* 00 */ + for (i = 0; i < 3; i++) { /* 00 */ secp256k1_scalar_sqr(t, t); + } secp256k1_scalar_mul(t, t, x); /* 1 */ - for (i = 0; i < 3; i++) /* 00 */ + for (i = 0; i < 3; i++) { /* 00 */ secp256k1_scalar_sqr(t, t); + } secp256k1_scalar_mul(t, t, x); /* 1 */ - for (i = 0; i < 5; i++) /* 0 */ + for (i = 0; i < 5; i++) { /* 0 */ secp256k1_scalar_sqr(t, t); + } secp256k1_scalar_mul(t, t, &x4); /* 1111 */ - for (i = 0; i < 2; i++) /* 0 */ + for (i = 0; i < 2; i++) { /* 0 */ secp256k1_scalar_sqr(t, t); + } secp256k1_scalar_mul(t, t, x); /* 1 */ - for (i = 0; i < 5; i++) /* 000 */ + for (i = 0; i < 5; i++) { /* 000 */ secp256k1_scalar_sqr(t, t); + } secp256k1_scalar_mul(t, t, &x2); /* 11 */ - for (i = 0; i < 4; i++) /* 00 */ + for (i = 0; i < 4; i++) { /* 00 */ secp256k1_scalar_sqr(t, t); + } secp256k1_scalar_mul(t, t, &x2); /* 11 */ - for (i = 0; i < 2; i++) /* 0 */ + for (i = 0; i < 2; i++) { /* 0 */ secp256k1_scalar_sqr(t, t); + } secp256k1_scalar_mul(t, t, x); /* 1 */ - for (i = 0; i < 8; i++) /* 000000 */ + for (i = 0; i < 8; i++) { /* 000000 */ secp256k1_scalar_sqr(t, t); + } secp256k1_scalar_mul(t, t, &x2); /* 11 */ - for (i = 0; i < 3; i++) /* 0 */ + for (i = 0; i < 3; i++) { /* 0 */ secp256k1_scalar_sqr(t, t); + } secp256k1_scalar_mul(t, t, &x2); /* 11 */ - for (i = 0; i < 3; i++) /* 00 */ + for (i = 0; i < 3; i++) { /* 00 */ secp256k1_scalar_sqr(t, t); + } secp256k1_scalar_mul(t, t, x); /* 1 */ - for (i = 0; i < 6; i++) /* 00000 */ + for (i = 0; i < 6; i++) { /* 00000 */ secp256k1_scalar_sqr(t, t); + } secp256k1_scalar_mul(t, t, x); /* 1 */ - for (i = 0; i < 8; i++) /* 00 */ + for (i = 0; i < 8; i++) { /* 00 */ secp256k1_scalar_sqr(t, t); + } secp256k1_scalar_mul(r, t, &x6); /* 111111 */ } diff --git a/src/secp256k1.c b/src/secp256k1.c index 8c4eca4b6..d6192dc4e 100644 --- a/src/secp256k1.c +++ b/src/secp256k1.c @@ -1,5 +1,5 @@ /********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * + * Copyright (c) 2013-2015 Pieter Wuille * * Distributed under the MIT software license, see the accompanying * * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ @@ -19,26 +19,48 @@ #include "eckey_impl.h" #include "hash_impl.h" -void secp256k1_start(unsigned int flags) { - if (flags & SECP256K1_START_SIGN) { - secp256k1_ecmult_gen_start(); +struct secp256k1_context_struct { + secp256k1_ecmult_context_t ecmult_ctx; + secp256k1_ecmult_gen_context_t ecmult_gen_ctx; +}; + +secp256k1_context_t* secp256k1_context_create(int flags) { + secp256k1_context_t* ret = (secp256k1_context_t*)checked_malloc(sizeof(secp256k1_context_t)); + + secp256k1_ecmult_context_init(&ret->ecmult_ctx); + secp256k1_ecmult_gen_context_init(&ret->ecmult_gen_ctx); + + if (flags & SECP256K1_CONTEXT_SIGN) { + secp256k1_ecmult_gen_context_build(&ret->ecmult_gen_ctx); } - if (flags & SECP256K1_START_VERIFY) { - secp256k1_ecmult_start(); + if (flags & SECP256K1_CONTEXT_VERIFY) { + secp256k1_ecmult_context_build(&ret->ecmult_ctx); } + + return ret; } -void secp256k1_stop(void) { - secp256k1_ecmult_stop(); - secp256k1_ecmult_gen_stop(); +secp256k1_context_t* secp256k1_context_clone(const secp256k1_context_t* ctx) { + secp256k1_context_t* ret = (secp256k1_context_t*)checked_malloc(sizeof(secp256k1_context_t)); + secp256k1_ecmult_context_clone(&ret->ecmult_ctx, &ctx->ecmult_ctx); + secp256k1_ecmult_gen_context_clone(&ret->ecmult_gen_ctx, &ctx->ecmult_gen_ctx); + return ret; } -int secp256k1_ecdsa_verify(const unsigned char *msg32, const unsigned char *sig, int siglen, const unsigned char *pubkey, int pubkeylen) { +void secp256k1_context_destroy(secp256k1_context_t* ctx) { + secp256k1_ecmult_context_clear(&ctx->ecmult_ctx); + secp256k1_ecmult_gen_context_clear(&ctx->ecmult_gen_ctx); + + free(ctx); +} + +int secp256k1_ecdsa_verify(const secp256k1_context_t* ctx, const unsigned char *msg32, const unsigned char *sig, int siglen, const unsigned char *pubkey, int pubkeylen) { secp256k1_ge_t q; secp256k1_ecdsa_sig_t s; secp256k1_scalar_t m; int ret = -3; - DEBUG_CHECK(secp256k1_ecmult_consts != NULL); + DEBUG_CHECK(ctx != NULL); + DEBUG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); DEBUG_CHECK(msg32 != NULL); DEBUG_CHECK(sig != NULL); DEBUG_CHECK(pubkey != NULL); @@ -47,7 +69,7 @@ int secp256k1_ecdsa_verify(const unsigned char *msg32, const unsigned char *sig, if (secp256k1_eckey_pubkey_parse(&q, pubkey, pubkeylen)) { if (secp256k1_ecdsa_sig_parse(&s, sig, siglen)) { - if (secp256k1_ecdsa_sig_verify(&s, &q, &m)) { + if (secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &s, &q, &m)) { /* success is 1, all other values are fail */ ret = 1; } else { @@ -66,7 +88,7 @@ int secp256k1_ecdsa_verify(const unsigned char *msg32, const unsigned char *sig, static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, unsigned int counter, const void *data) { secp256k1_rfc6979_hmac_sha256_t rng; unsigned int i; - secp256k1_rfc6979_hmac_sha256_initialize(&rng, key32, 32, msg32, 32, data, data != NULL ? 32 : 0); + secp256k1_rfc6979_hmac_sha256_initialize(&rng, key32, 32, msg32, 32, (const unsigned char*)data, data != NULL ? 32 : 0); for (i = 0; i <= counter; i++) { secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32); } @@ -77,13 +99,14 @@ static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *m const secp256k1_nonce_function_t secp256k1_nonce_function_rfc6979 = nonce_function_rfc6979; const secp256k1_nonce_function_t secp256k1_nonce_function_default = nonce_function_rfc6979; -int secp256k1_ecdsa_sign(const unsigned char *msg32, unsigned char *signature, int *signaturelen, const unsigned char *seckey, secp256k1_nonce_function_t noncefp, const void* noncedata) { +int secp256k1_ecdsa_sign(const secp256k1_context_t* ctx, const unsigned char *msg32, unsigned char *signature, int *signaturelen, const unsigned char *seckey, secp256k1_nonce_function_t noncefp, const void* noncedata) { secp256k1_ecdsa_sig_t sig; secp256k1_scalar_t sec, non, msg; int ret = 0; int overflow = 0; unsigned int count = 0; - DEBUG_CHECK(secp256k1_ecmult_gen_consts != NULL); + DEBUG_CHECK(ctx != NULL); + DEBUG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); DEBUG_CHECK(msg32 != NULL); DEBUG_CHECK(signature != NULL); DEBUG_CHECK(signaturelen != NULL); @@ -105,7 +128,7 @@ int secp256k1_ecdsa_sign(const unsigned char *msg32, unsigned char *signature, i secp256k1_scalar_set_b32(&non, nonce32, &overflow); memset(nonce32, 0, 32); if (!secp256k1_scalar_is_zero(&non) && !overflow) { - if (secp256k1_ecdsa_sig_sign(&sig, &sec, &msg, &non, NULL)) { + if (secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, &sig, &sec, &msg, &non, NULL)) { break; } } @@ -124,13 +147,14 @@ int secp256k1_ecdsa_sign(const unsigned char *msg32, unsigned char *signature, i return ret; } -int secp256k1_ecdsa_sign_compact(const unsigned char *msg32, unsigned char *sig64, const unsigned char *seckey, secp256k1_nonce_function_t noncefp, const void* noncedata, int *recid) { +int secp256k1_ecdsa_sign_compact(const secp256k1_context_t* ctx, const unsigned char *msg32, unsigned char *sig64, const unsigned char *seckey, secp256k1_nonce_function_t noncefp, const void* noncedata, int *recid) { secp256k1_ecdsa_sig_t sig; secp256k1_scalar_t sec, non, msg; int ret = 0; int overflow = 0; unsigned int count = 0; - DEBUG_CHECK(secp256k1_ecmult_gen_consts != NULL); + DEBUG_CHECK(ctx != NULL); + DEBUG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); DEBUG_CHECK(msg32 != NULL); DEBUG_CHECK(sig64 != NULL); DEBUG_CHECK(seckey != NULL); @@ -151,7 +175,7 @@ int secp256k1_ecdsa_sign_compact(const unsigned char *msg32, unsigned char *sig6 secp256k1_scalar_set_b32(&non, nonce32, &overflow); memset(nonce32, 0, 32); if (!secp256k1_scalar_is_zero(&non) && !overflow) { - if (secp256k1_ecdsa_sig_sign(&sig, &sec, &msg, &non, recid)) { + if (secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, &sig, &sec, &msg, &non, recid)) { break; } } @@ -171,13 +195,14 @@ int secp256k1_ecdsa_sign_compact(const unsigned char *msg32, unsigned char *sig6 return ret; } -int secp256k1_ecdsa_recover_compact(const unsigned char *msg32, const unsigned char *sig64, unsigned char *pubkey, int *pubkeylen, int compressed, int recid) { +int secp256k1_ecdsa_recover_compact(const secp256k1_context_t* ctx, const unsigned char *msg32, const unsigned char *sig64, unsigned char *pubkey, int *pubkeylen, int compressed, int recid) { secp256k1_ge_t q; secp256k1_ecdsa_sig_t sig; secp256k1_scalar_t m; int ret = 0; int overflow = 0; - DEBUG_CHECK(secp256k1_ecmult_consts != NULL); + DEBUG_CHECK(ctx != NULL); + DEBUG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); DEBUG_CHECK(msg32 != NULL); DEBUG_CHECK(sig64 != NULL); DEBUG_CHECK(pubkey != NULL); @@ -190,7 +215,7 @@ int secp256k1_ecdsa_recover_compact(const unsigned char *msg32, const unsigned c if (!overflow) { secp256k1_scalar_set_b32(&m, msg32, NULL); - if (secp256k1_ecdsa_sig_recover(&sig, &q, &m, recid)) { + if (secp256k1_ecdsa_sig_recover(&ctx->ecmult_ctx, &sig, &q, &m, recid)) { ret = secp256k1_eckey_pubkey_serialize(&q, pubkey, pubkeylen, compressed); } } @@ -198,11 +223,13 @@ int secp256k1_ecdsa_recover_compact(const unsigned char *msg32, const unsigned c return ret; } -int secp256k1_ec_seckey_verify(const unsigned char *seckey) { +int secp256k1_ec_seckey_verify(const secp256k1_context_t* ctx, const unsigned char *seckey) { secp256k1_scalar_t sec; int ret; int overflow; + DEBUG_CHECK(ctx != NULL); DEBUG_CHECK(seckey != NULL); + (void)ctx; secp256k1_scalar_set_b32(&sec, seckey, &overflow); ret = !secp256k1_scalar_is_zero(&sec) && !overflow; @@ -210,27 +237,30 @@ int secp256k1_ec_seckey_verify(const unsigned char *seckey) { return ret; } -int secp256k1_ec_pubkey_verify(const unsigned char *pubkey, int pubkeylen) { +int secp256k1_ec_pubkey_verify(const secp256k1_context_t* ctx, const unsigned char *pubkey, int pubkeylen) { secp256k1_ge_t q; + DEBUG_CHECK(ctx != NULL); DEBUG_CHECK(pubkey != NULL); + (void)ctx; return secp256k1_eckey_pubkey_parse(&q, pubkey, pubkeylen); } -int secp256k1_ec_pubkey_create(unsigned char *pubkey, int *pubkeylen, const unsigned char *seckey, int compressed) { +int secp256k1_ec_pubkey_create(const secp256k1_context_t* ctx, unsigned char *pubkey, int *pubkeylen, const unsigned char *seckey, int compressed) { secp256k1_gej_t pj; secp256k1_ge_t p; secp256k1_scalar_t sec; int overflow; int ret = 0; - DEBUG_CHECK(secp256k1_ecmult_gen_consts != NULL); + DEBUG_CHECK(ctx != NULL); + DEBUG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); DEBUG_CHECK(pubkey != NULL); DEBUG_CHECK(pubkeylen != NULL); DEBUG_CHECK(seckey != NULL); secp256k1_scalar_set_b32(&sec, seckey, &overflow); if (!overflow) { - secp256k1_ecmult_gen(&pj, &sec); + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pj, &sec); secp256k1_scalar_clear(&sec); secp256k1_ge_set_gej(&p, &pj); ret = secp256k1_eckey_pubkey_serialize(&p, pubkey, pubkeylen, compressed); @@ -241,11 +271,12 @@ int secp256k1_ec_pubkey_create(unsigned char *pubkey, int *pubkeylen, const unsi return ret; } -int secp256k1_ec_pubkey_decompress(unsigned char *pubkey, int *pubkeylen) { +int secp256k1_ec_pubkey_decompress(const secp256k1_context_t* ctx, unsigned char *pubkey, int *pubkeylen) { secp256k1_ge_t p; int ret = 0; DEBUG_CHECK(pubkey != NULL); DEBUG_CHECK(pubkeylen != NULL); + (void)ctx; if (secp256k1_eckey_pubkey_parse(&p, pubkey, *pubkeylen)) { ret = secp256k1_eckey_pubkey_serialize(&p, pubkey, pubkeylen, 0); @@ -253,13 +284,15 @@ int secp256k1_ec_pubkey_decompress(unsigned char *pubkey, int *pubkeylen) { return ret; } -int secp256k1_ec_privkey_tweak_add(unsigned char *seckey, const unsigned char *tweak) { +int secp256k1_ec_privkey_tweak_add(const secp256k1_context_t* ctx, unsigned char *seckey, const unsigned char *tweak) { secp256k1_scalar_t term; secp256k1_scalar_t sec; int ret = 0; int overflow = 0; + DEBUG_CHECK(ctx != NULL); DEBUG_CHECK(seckey != NULL); DEBUG_CHECK(tweak != NULL); + (void)ctx; secp256k1_scalar_set_b32(&term, tweak, &overflow); secp256k1_scalar_set_b32(&sec, seckey, NULL); @@ -274,12 +307,13 @@ int secp256k1_ec_privkey_tweak_add(unsigned char *seckey, const unsigned char *t return ret; } -int secp256k1_ec_pubkey_tweak_add(unsigned char *pubkey, int pubkeylen, const unsigned char *tweak) { +int secp256k1_ec_pubkey_tweak_add(const secp256k1_context_t* ctx, unsigned char *pubkey, int pubkeylen, const unsigned char *tweak) { secp256k1_ge_t p; secp256k1_scalar_t term; int ret = 0; int overflow = 0; - DEBUG_CHECK(secp256k1_ecmult_consts != NULL); + DEBUG_CHECK(ctx != NULL); + DEBUG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); DEBUG_CHECK(pubkey != NULL); DEBUG_CHECK(tweak != NULL); @@ -287,7 +321,7 @@ int secp256k1_ec_pubkey_tweak_add(unsigned char *pubkey, int pubkeylen, const un if (!overflow) { ret = secp256k1_eckey_pubkey_parse(&p, pubkey, pubkeylen); if (ret) { - ret = secp256k1_eckey_pubkey_tweak_add(&p, &term); + ret = secp256k1_eckey_pubkey_tweak_add(&ctx->ecmult_ctx, &p, &term); } if (ret) { int oldlen = pubkeylen; @@ -299,13 +333,15 @@ int secp256k1_ec_pubkey_tweak_add(unsigned char *pubkey, int pubkeylen, const un return ret; } -int secp256k1_ec_privkey_tweak_mul(unsigned char *seckey, const unsigned char *tweak) { +int secp256k1_ec_privkey_tweak_mul(const secp256k1_context_t* ctx, unsigned char *seckey, const unsigned char *tweak) { secp256k1_scalar_t factor; secp256k1_scalar_t sec; int ret = 0; int overflow = 0; + DEBUG_CHECK(ctx != NULL); DEBUG_CHECK(seckey != NULL); DEBUG_CHECK(tweak != NULL); + (void)ctx; secp256k1_scalar_set_b32(&factor, tweak, &overflow); secp256k1_scalar_set_b32(&sec, seckey, NULL); @@ -319,12 +355,13 @@ int secp256k1_ec_privkey_tweak_mul(unsigned char *seckey, const unsigned char *t return ret; } -int secp256k1_ec_pubkey_tweak_mul(unsigned char *pubkey, int pubkeylen, const unsigned char *tweak) { +int secp256k1_ec_pubkey_tweak_mul(const secp256k1_context_t* ctx, unsigned char *pubkey, int pubkeylen, const unsigned char *tweak) { secp256k1_ge_t p; secp256k1_scalar_t factor; int ret = 0; int overflow = 0; - DEBUG_CHECK(secp256k1_ecmult_consts != NULL); + DEBUG_CHECK(ctx != NULL); + DEBUG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); DEBUG_CHECK(pubkey != NULL); DEBUG_CHECK(tweak != NULL); @@ -332,7 +369,7 @@ int secp256k1_ec_pubkey_tweak_mul(unsigned char *pubkey, int pubkeylen, const un if (!overflow) { ret = secp256k1_eckey_pubkey_parse(&p, pubkey, pubkeylen); if (ret) { - ret = secp256k1_eckey_pubkey_tweak_mul(&p, &factor); + ret = secp256k1_eckey_pubkey_tweak_mul(&ctx->ecmult_ctx, &p, &factor); } if (ret) { int oldlen = pubkeylen; @@ -344,24 +381,27 @@ int secp256k1_ec_pubkey_tweak_mul(unsigned char *pubkey, int pubkeylen, const un return ret; } -int secp256k1_ec_privkey_export(const unsigned char *seckey, unsigned char *privkey, int *privkeylen, int compressed) { +int secp256k1_ec_privkey_export(const secp256k1_context_t* ctx, const unsigned char *seckey, unsigned char *privkey, int *privkeylen, int compressed) { secp256k1_scalar_t key; int ret = 0; DEBUG_CHECK(seckey != NULL); DEBUG_CHECK(privkey != NULL); DEBUG_CHECK(privkeylen != NULL); + DEBUG_CHECK(ctx != NULL); + DEBUG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); secp256k1_scalar_set_b32(&key, seckey, NULL); - ret = secp256k1_eckey_privkey_serialize(privkey, privkeylen, &key, compressed); + ret = secp256k1_eckey_privkey_serialize(&ctx->ecmult_gen_ctx, privkey, privkeylen, &key, compressed); secp256k1_scalar_clear(&key); return ret; } -int secp256k1_ec_privkey_import(unsigned char *seckey, const unsigned char *privkey, int privkeylen) { +int secp256k1_ec_privkey_import(const secp256k1_context_t* ctx, unsigned char *seckey, const unsigned char *privkey, int privkeylen) { secp256k1_scalar_t key; int ret = 0; DEBUG_CHECK(seckey != NULL); DEBUG_CHECK(privkey != NULL); + (void)ctx; ret = secp256k1_eckey_privkey_parse(&key, privkey, privkeylen); if (ret) { @@ -370,3 +410,10 @@ int secp256k1_ec_privkey_import(unsigned char *seckey, const unsigned char *priv secp256k1_scalar_clear(&key); return ret; } + +int secp256k1_context_randomize(secp256k1_context_t* ctx, const unsigned char *seed32) { + DEBUG_CHECK(ctx != NULL); + DEBUG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, seed32); + return 1; +} diff --git a/src/tests.c b/src/tests.c index f7f1acac6..d0e05057f 100644 --- a/src/tests.c +++ b/src/tests.c @@ -1,5 +1,5 @@ /********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * + * Copyright (c) 2013, 2014, 2015 Pieter Wuille, Gregory Maxwell * * Distributed under the MIT software license, see the accompanying * * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ @@ -24,6 +24,7 @@ #endif static int count = 64; +static secp256k1_context_t *ctx = NULL; void random_field_element_test(secp256k1_fe_t *fe) { do { @@ -55,8 +56,9 @@ void random_group_element_test(secp256k1_ge_t *ge) { secp256k1_fe_t fe; do { random_field_element_test(&fe); - if (secp256k1_ge_set_xo_var(ge, &fe, secp256k1_rand32() & 1)) + if (secp256k1_ge_set_xo_var(ge, &fe, secp256k1_rand32() & 1)) { break; + } } while(1); } @@ -81,8 +83,9 @@ void random_scalar_order_test(secp256k1_scalar_t *num) { int overflow = 0; secp256k1_rand256_test(b32); secp256k1_scalar_set_b32(num, b32, &overflow); - if (overflow || secp256k1_scalar_is_zero(num)) + if (overflow || secp256k1_scalar_is_zero(num)) { continue; + } break; } while(1); } @@ -93,12 +96,60 @@ void random_scalar_order(secp256k1_scalar_t *num) { int overflow = 0; secp256k1_rand256(b32); secp256k1_scalar_set_b32(num, b32, &overflow); - if (overflow || secp256k1_scalar_is_zero(num)) + if (overflow || secp256k1_scalar_is_zero(num)) { continue; + } break; } while(1); } +void run_context_tests(void) { + secp256k1_context_t *none = secp256k1_context_create(0); + secp256k1_context_t *sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); + secp256k1_context_t *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY); + secp256k1_context_t *both = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + + secp256k1_gej_t pubj; + secp256k1_ge_t pub; + secp256k1_scalar_t msg, key, nonce; + secp256k1_ecdsa_sig_t sig; + + /*** clone and destroy all of them to make sure cloning was complete ***/ + { + secp256k1_context_t *ctx_tmp; + + ctx_tmp = none; none = secp256k1_context_clone(none); secp256k1_context_destroy(ctx_tmp); + ctx_tmp = sign; sign = secp256k1_context_clone(sign); secp256k1_context_destroy(ctx_tmp); + ctx_tmp = vrfy; vrfy = secp256k1_context_clone(vrfy); secp256k1_context_destroy(ctx_tmp); + ctx_tmp = both; both = secp256k1_context_clone(both); secp256k1_context_destroy(ctx_tmp); + } + + /*** attempt to use them ***/ + random_scalar_order_test(&msg); + random_scalar_order_test(&key); + secp256k1_ecmult_gen(&both->ecmult_gen_ctx, &pubj, &key); + secp256k1_ge_set_gej(&pub, &pubj); + + /* obtain a working nonce */ + do { + random_scalar_order_test(&nonce); + } while(!secp256k1_ecdsa_sig_sign(&both->ecmult_gen_ctx, &sig, &key, &msg, &nonce, NULL)); + + /* try signing */ + CHECK(secp256k1_ecdsa_sig_sign(&sign->ecmult_gen_ctx, &sig, &key, &msg, &nonce, NULL)); + CHECK(secp256k1_ecdsa_sig_sign(&both->ecmult_gen_ctx, &sig, &key, &msg, &nonce, NULL)); + + /* try verifying */ + CHECK(secp256k1_ecdsa_sig_verify(&vrfy->ecmult_ctx, &sig, &pub, &msg)); + CHECK(secp256k1_ecdsa_sig_verify(&both->ecmult_ctx, &sig, &pub, &msg)); + + /* cleanup */ + secp256k1_context_destroy(none); + secp256k1_context_destroy(sign); + secp256k1_context_destroy(vrfy); + secp256k1_context_destroy(both); +} + /***** HASH TESTS *****/ void run_sha256_tests(void) { @@ -229,8 +280,9 @@ void run_rfc6979_hmac_sha256_tests(void) { #ifndef USE_NUM_NONE void random_num_negate(secp256k1_num_t *num) { - if (secp256k1_rand32() & 1) + if (secp256k1_rand32() & 1) { secp256k1_num_negate(num); + } } void random_num_order_test(secp256k1_num_t *num) { @@ -624,8 +676,9 @@ void random_fe_non_zero(secp256k1_fe_t *nz) { while (--tries >= 0) { random_fe(nz); secp256k1_fe_normalize(nz); - if (!secp256k1_fe_is_zero(nz)) + if (!secp256k1_fe_is_zero(nz)) { break; + } } /* Infinitesimal probability of spurious failure here */ CHECK(tries >= 0); @@ -700,12 +753,22 @@ void run_field_misc(void) { CHECK(secp256k1_fe_equal_var(&x, &x)); z = x; secp256k1_fe_add(&z,&y); - secp256k1_fe_normalize(&z); + /* Test fe conditional move; z is not normalized here. */ + q = x; + secp256k1_fe_cmov(&x, &z, 0); + secp256k1_fe_cmov(&x, &x, 1); + CHECK(memcmp(&x, &z, sizeof(x)) != 0); + CHECK(memcmp(&x, &q, sizeof(x)) == 0); + secp256k1_fe_cmov(&q, &z, 1); + CHECK(memcmp(&q, &z, sizeof(q)) == 0); /* Test storage conversion and conditional moves. */ + secp256k1_fe_normalize(&z); + CHECK(!secp256k1_fe_equal_var(&x, &z)); secp256k1_fe_to_storage(&xs, &x); secp256k1_fe_to_storage(&ys, &y); secp256k1_fe_to_storage(&zs, &z); secp256k1_fe_storage_cmov(&zs, &xs, 0); + secp256k1_fe_storage_cmov(&zs, &zs, 1); CHECK(memcmp(&xs, &zs, sizeof(xs)) != 0); secp256k1_fe_storage_cmov(&ys, &xs, 1); CHECK(memcmp(&xs, &ys, sizeof(xs)) == 0); @@ -765,14 +828,17 @@ void run_field_inv_all_var(void) { for (i = 0; i < count; i++) { size_t j; size_t len = (secp256k1_rand32() & 15) + 1; - for (j = 0; j < len; j++) + for (j = 0; j < len; j++) { random_fe_non_zero(&x[j]); + } secp256k1_fe_inv_all_var(len, xi, x); - for (j = 0; j < len; j++) + for (j = 0; j < len; j++) { CHECK(check_fe_inverse(&x[j], &xi[j])); + } secp256k1_fe_inv_all_var(len, xii, xi); - for (j = 0; j < len; j++) + for (j = 0; j < len; j++) { CHECK(check_fe_equal(&x[j], &xii[j])); + } } } @@ -844,18 +910,42 @@ void run_sqrt(void) { void ge_equals_ge(const secp256k1_ge_t *a, const secp256k1_ge_t *b) { CHECK(a->infinity == b->infinity); - if (a->infinity) + if (a->infinity) { return; + } CHECK(secp256k1_fe_equal_var(&a->x, &b->x)); CHECK(secp256k1_fe_equal_var(&b->y, &b->y)); } +/* This compares jacobian points including their Z, not just their geometric meaning. */ +int gej_xyz_equals_gej(const secp256k1_gej_t *a, const secp256k1_gej_t *b) { + secp256k1_gej_t a2; + secp256k1_gej_t b2; + int ret = 1; + ret &= a->infinity == b->infinity; + if (ret && !a->infinity) { + a2 = *a; + b2 = *b; + secp256k1_fe_normalize(&a2.x); + secp256k1_fe_normalize(&a2.y); + secp256k1_fe_normalize(&a2.z); + secp256k1_fe_normalize(&b2.x); + secp256k1_fe_normalize(&b2.y); + secp256k1_fe_normalize(&b2.z); + ret &= secp256k1_fe_cmp_var(&a2.x, &b2.x) == 0; + ret &= secp256k1_fe_cmp_var(&a2.y, &b2.y) == 0; + ret &= secp256k1_fe_cmp_var(&a2.z, &b2.z) == 0; + } + return ret; +} + void ge_equals_gej(const secp256k1_ge_t *a, const secp256k1_gej_t *b) { secp256k1_fe_t z2s; secp256k1_fe_t u1, u2, s1, s2; CHECK(a->infinity == b->infinity); - if (a->infinity) + if (a->infinity) { return; + } /* Check a.x * b.z^2 == b.x && a.y * b.z^3 == b.y, to avoid inverses. */ secp256k1_fe_sqr(&z2s, &b->z); secp256k1_fe_mul(&u1, &a->x, &z2s); @@ -874,8 +964,8 @@ void test_ge(void) { * All magnitudes are randomized. * All 17*17 combinations of points are added to eachother, using all applicable methods. */ - secp256k1_ge_t *ge = malloc(sizeof(secp256k1_ge_t) * (1 + 4 * runs)); - secp256k1_gej_t *gej = malloc(sizeof(secp256k1_gej_t) * (1 + 4 * runs)); + secp256k1_ge_t *ge = (secp256k1_ge_t *)malloc(sizeof(secp256k1_ge_t) * (1 + 4 * runs)); + secp256k1_gej_t *gej = (secp256k1_gej_t *)malloc(sizeof(secp256k1_gej_t) * (1 + 4 * runs)); secp256k1_gej_set_infinity(&gej[0]); secp256k1_ge_clear(&ge[0]); secp256k1_ge_set_gej_var(&ge[0], &gej[0]); @@ -951,7 +1041,7 @@ void test_ge(void) { /* Test adding all points together in random order equals infinity. */ { secp256k1_gej_t sum = SECP256K1_GEJ_CONST_INFINITY; - secp256k1_gej_t *gej_shuffled = malloc((4 * runs + 1) * sizeof(secp256k1_gej_t)); + secp256k1_gej_t *gej_shuffled = (secp256k1_gej_t *)malloc((4 * runs + 1) * sizeof(secp256k1_gej_t)); for (i = 0; i < 4 * runs + 1; i++) { gej_shuffled[i] = gej[i]; } @@ -972,9 +1062,12 @@ void test_ge(void) { /* Test batch gej -> ge conversion. */ { - secp256k1_ge_t *ge_set_all = malloc((4 * runs + 1) * sizeof(secp256k1_ge_t)); + secp256k1_ge_t *ge_set_all = (secp256k1_ge_t *)malloc((4 * runs + 1) * sizeof(secp256k1_ge_t)); secp256k1_ge_set_all_gej_var(4 * runs + 1, ge_set_all, gej); for (i = 0; i < 4 * runs + 1; i++) { + secp256k1_fe_t s; + random_fe_non_zero(&s); + secp256k1_gej_rescale(&gej[i], &s); ge_equals_gej(&ge_set_all[i], &gej[i]); } free(ge_set_all); @@ -1025,7 +1118,7 @@ void run_ecmult_chain(void) { x = a; for (i = 0; i < 200*count; i++) { /* in each iteration, compute X = xn*X + gn*G; */ - secp256k1_ecmult(&x, &x, &xn, &gn); + secp256k1_ecmult(&ctx->ecmult_ctx, &x, &x, &xn, &gn); /* also compute ae and ge: the actual accumulated factors for A and G */ /* if X was (ae*A+ge*G), xn*X + gn*G results in (xn*ae*A + (xn*ge+gn)*G) */ secp256k1_scalar_mul(&ae, &ae, &xn); @@ -1051,7 +1144,7 @@ void run_ecmult_chain(void) { } } /* redo the computation, but directly with the resulting ae and ge coefficients: */ - secp256k1_ecmult(&x2, &a, &ae, &ge); + secp256k1_ecmult(&ctx->ecmult_ctx, &x2, &a, &ae, &ge); secp256k1_gej_neg(&x2, &x2); secp256k1_gej_add_var(&x2, &x2, &x); CHECK(secp256k1_gej_is_infinity(&x2)); @@ -1067,8 +1160,8 @@ void test_point_times_order(const secp256k1_gej_t *point) { int psize = 65; random_scalar_order_test(&x); secp256k1_scalar_negate(&nx, &x); - secp256k1_ecmult(&res1, point, &x, &x); /* calc res1 = x * point + x * G; */ - secp256k1_ecmult(&res2, point, &nx, &nx); /* calc res2 = (order - x) * point + (order - x) * G; */ + secp256k1_ecmult(&ctx->ecmult_ctx, &res1, point, &x, &x); /* calc res1 = x * point + x * G; */ + secp256k1_ecmult(&ctx->ecmult_ctx, &res2, point, &nx, &nx); /* calc res2 = (order - x) * point + (order - x) * G; */ secp256k1_gej_add_var(&res1, &res1, &res2); CHECK(secp256k1_gej_is_infinity(&res1)); CHECK(secp256k1_gej_is_valid_var(&res1) == 0); @@ -1141,17 +1234,96 @@ void run_wnaf(void) { secp256k1_scalar_t n; for (i = 0; i < count; i++) { random_scalar_order(&n); - if (i % 1) - secp256k1_scalar_negate(&n, &n); test_wnaf(&n, 4+(i%10)); } } +void test_ecmult_constants(void) { + /* Test ecmult_gen() for [0..36) and [order-36..0). */ + secp256k1_scalar_t x; + secp256k1_gej_t r; + secp256k1_ge_t ng; + int i; + int j; + secp256k1_ge_neg(&ng, &secp256k1_ge_const_g); + for (i = 0; i < 36; i++ ) { + secp256k1_scalar_set_int(&x, i); + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &r, &x); + for (j = 0; j < i; j++) { + if (j == i - 1) { + ge_equals_gej(&secp256k1_ge_const_g, &r); + } + secp256k1_gej_add_ge(&r, &r, &ng); + } + CHECK(secp256k1_gej_is_infinity(&r)); + } + for (i = 1; i <= 36; i++ ) { + secp256k1_scalar_set_int(&x, i); + secp256k1_scalar_negate(&x, &x); + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &r, &x); + for (j = 0; j < i; j++) { + if (j == i - 1) { + ge_equals_gej(&ng, &r); + } + secp256k1_gej_add_ge(&r, &r, &secp256k1_ge_const_g); + } + CHECK(secp256k1_gej_is_infinity(&r)); + } +} + +void run_ecmult_constants(void) { + test_ecmult_constants(); +} + +void test_ecmult_gen_blind(void) { + /* Test ecmult_gen() blinding and confirm that the blinding changes, the affline points match, and the z's don't match. */ + secp256k1_scalar_t key; + secp256k1_scalar_t b; + unsigned char seed32[32]; + secp256k1_gej_t pgej; + secp256k1_gej_t pgej2; + secp256k1_gej_t i; + secp256k1_ge_t pge; + random_scalar_order_test(&key); + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pgej, &key); + secp256k1_rand256(seed32); + b = ctx->ecmult_gen_ctx.blind; + i = ctx->ecmult_gen_ctx.initial; + secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, seed32); + CHECK(!secp256k1_scalar_eq(&b, &ctx->ecmult_gen_ctx.blind)); + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pgej2, &key); + CHECK(!gej_xyz_equals_gej(&pgej, &pgej2)); + CHECK(!gej_xyz_equals_gej(&i, &ctx->ecmult_gen_ctx.initial)); + secp256k1_ge_set_gej(&pge, &pgej); + ge_equals_gej(&pge, &pgej2); +} + +void test_ecmult_gen_blind_reset(void) { + /* Test ecmult_gen() blinding reset and confirm that the blinding is consistent. */ + secp256k1_scalar_t b; + secp256k1_gej_t initial; + secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, 0); + b = ctx->ecmult_gen_ctx.blind; + initial = ctx->ecmult_gen_ctx.initial; + secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, 0); + CHECK(secp256k1_scalar_eq(&b, &ctx->ecmult_gen_ctx.blind)); + CHECK(gej_xyz_equals_gej(&initial, &ctx->ecmult_gen_ctx.initial)); +} + +void run_ecmult_gen_blind(void) { + int i; + test_ecmult_gen_blind_reset(); + for (i = 0; i < 10; i++) { + test_ecmult_gen_blind(); + } +} + + void random_sign(secp256k1_ecdsa_sig_t *sig, const secp256k1_scalar_t *key, const secp256k1_scalar_t *msg, int *recid) { secp256k1_scalar_t nonce; do { random_scalar_order_test(&nonce); - } while(!secp256k1_ecdsa_sig_sign(sig, key, msg, &nonce, recid)); + } while(!secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, sig, key, msg, &nonce, recid)); } void test_ecdsa_sign_verify(void) { @@ -1164,15 +1336,17 @@ void test_ecdsa_sign_verify(void) { int getrec; random_scalar_order_test(&msg); random_scalar_order_test(&key); - secp256k1_ecmult_gen(&pubj, &key); + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pubj, &key); secp256k1_ge_set_gej(&pub, &pubj); getrec = secp256k1_rand32()&1; random_sign(&sig, &key, &msg, getrec?&recid:NULL); - if (getrec) CHECK(recid >= 0 && recid < 4); - CHECK(secp256k1_ecdsa_sig_verify(&sig, &pub, &msg)); + if (getrec) { + CHECK(recid >= 0 && recid < 4); + } + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sig, &pub, &msg)); secp256k1_scalar_set_int(&one, 1); secp256k1_scalar_add(&msg, &msg, &one); - CHECK(!secp256k1_ecdsa_sig_verify(&sig, &pub, &msg)); + CHECK(!secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sig, &pub, &msg)); } void run_ecdsa_sign_verify(void) { @@ -1192,7 +1366,9 @@ static int precomputed_nonce_function(unsigned char *nonce32, const unsigned cha static int nonce_function_test_fail(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, unsigned int counter, const void *data) { /* Dummy nonce generator that has a fatal error on the first counter value. */ - if (counter == 0) return 0; + if (counter == 0) { + return 0; + } return nonce_function_rfc6979(nonce32, msg32, key32, counter - 1, data); } @@ -1200,7 +1376,9 @@ static int nonce_function_test_retry(unsigned char *nonce32, const unsigned char /* Dummy nonce generator that produces unacceptable nonces for the first several counter values. */ if (counter < 3) { memset(nonce32, counter==0 ? 0 : 255, 32); - if (counter == 2) nonce32[31]--; + if (counter == 2) { + nonce32[31]--; + } return 1; } if (counter < 5) { @@ -1211,12 +1389,16 @@ static int nonce_function_test_retry(unsigned char *nonce32, const unsigned char 0xBF,0xD2,0x5E,0x8C,0xD0,0x36,0x41,0x41 }; memcpy(nonce32, order, 32); - if (counter == 4) nonce32[31]++; + if (counter == 4) { + nonce32[31]++; + } return 1; } /* Retry rate of 6979 is negligible esp. as we only call this in determinstic tests. */ /* If someone does fine a case where it retries for secp256k1, we'd like to know. */ - if (counter > 5) return 0; + if (counter > 5) { + return 0; + } return nonce_function_rfc6979(nonce32, msg32, key32, counter - 5, data); } @@ -1257,16 +1439,16 @@ void test_ecdsa_end_to_end(void) { } /* Construct and verify corresponding public key. */ - CHECK(secp256k1_ec_seckey_verify(privkey) == 1); - CHECK(secp256k1_ec_pubkey_create(pubkey, &pubkeylen, privkey, (secp256k1_rand32() & 3) != 0) == 1); + CHECK(secp256k1_ec_seckey_verify(ctx, privkey) == 1); + CHECK(secp256k1_ec_pubkey_create(ctx, pubkey, &pubkeylen, privkey, (secp256k1_rand32() & 3) != 0) == 1); if (secp256k1_rand32() & 1) { - CHECK(secp256k1_ec_pubkey_decompress(pubkey, &pubkeylen)); + CHECK(secp256k1_ec_pubkey_decompress(ctx, pubkey, &pubkeylen)); } - CHECK(secp256k1_ec_pubkey_verify(pubkey, pubkeylen)); + CHECK(secp256k1_ec_pubkey_verify(ctx, pubkey, pubkeylen)); /* Verify private key import and export. */ - CHECK(secp256k1_ec_privkey_export(privkey, seckey, &seckeylen, secp256k1_rand32() % 2) == 1); - CHECK(secp256k1_ec_privkey_import(privkey2, seckey, seckeylen) == 1); + CHECK(secp256k1_ec_privkey_export(ctx, privkey, seckey, &seckeylen, secp256k1_rand32() % 2) == 1); + CHECK(secp256k1_ec_privkey_import(ctx, privkey2, seckey, seckeylen) == 1); CHECK(memcmp(privkey, privkey2, 32) == 0); /* Optionally tweak the keys using addition. */ @@ -1277,11 +1459,13 @@ void test_ecdsa_end_to_end(void) { unsigned char pubkey2[65]; int pubkeylen2 = 65; secp256k1_rand256_test(rnd); - ret1 = secp256k1_ec_privkey_tweak_add(privkey, rnd); - ret2 = secp256k1_ec_pubkey_tweak_add(pubkey, pubkeylen, rnd); + ret1 = secp256k1_ec_privkey_tweak_add(ctx, privkey, rnd); + ret2 = secp256k1_ec_pubkey_tweak_add(ctx, pubkey, pubkeylen, rnd); CHECK(ret1 == ret2); - if (ret1 == 0) return; - CHECK(secp256k1_ec_pubkey_create(pubkey2, &pubkeylen2, privkey, pubkeylen == 33) == 1); + if (ret1 == 0) { + return; + } + CHECK(secp256k1_ec_pubkey_create(ctx, pubkey2, &pubkeylen2, privkey, pubkeylen == 33) == 1); CHECK(memcmp(pubkey, pubkey2, pubkeylen) == 0); } @@ -1293,25 +1477,27 @@ void test_ecdsa_end_to_end(void) { unsigned char pubkey2[65]; int pubkeylen2 = 65; secp256k1_rand256_test(rnd); - ret1 = secp256k1_ec_privkey_tweak_mul(privkey, rnd); - ret2 = secp256k1_ec_pubkey_tweak_mul(pubkey, pubkeylen, rnd); + ret1 = secp256k1_ec_privkey_tweak_mul(ctx, privkey, rnd); + ret2 = secp256k1_ec_pubkey_tweak_mul(ctx, pubkey, pubkeylen, rnd); CHECK(ret1 == ret2); - if (ret1 == 0) return; - CHECK(secp256k1_ec_pubkey_create(pubkey2, &pubkeylen2, privkey, pubkeylen == 33) == 1); + if (ret1 == 0) { + return; + } + CHECK(secp256k1_ec_pubkey_create(ctx, pubkey2, &pubkeylen2, privkey, pubkeylen == 33) == 1); CHECK(memcmp(pubkey, pubkey2, pubkeylen) == 0); } /* Sign. */ - CHECK(secp256k1_ecdsa_sign(message, signature, &signaturelen, privkey, NULL, NULL) == 1); + CHECK(secp256k1_ecdsa_sign(ctx, message, signature, &signaturelen, privkey, NULL, NULL) == 1); CHECK(signaturelen > 0); - CHECK(secp256k1_ecdsa_sign(message, signature2, &signaturelen2, privkey, NULL, extra) == 1); + CHECK(secp256k1_ecdsa_sign(ctx, message, signature2, &signaturelen2, privkey, NULL, extra) == 1); CHECK(signaturelen2 > 0); extra[31] = 1; - CHECK(secp256k1_ecdsa_sign(message, signature3, &signaturelen3, privkey, NULL, extra) == 1); + CHECK(secp256k1_ecdsa_sign(ctx, message, signature3, &signaturelen3, privkey, NULL, extra) == 1); CHECK(signaturelen3 > 0); extra[31] = 0; extra[0] = 1; - CHECK(secp256k1_ecdsa_sign(message, signature4, &signaturelen4, privkey, NULL, extra) == 1); + CHECK(secp256k1_ecdsa_sign(ctx, message, signature4, &signaturelen4, privkey, NULL, extra) == 1); CHECK(signaturelen3 > 0); CHECK((signaturelen != signaturelen2) || (memcmp(signature, signature2, signaturelen) != 0)); CHECK((signaturelen != signaturelen3) || (memcmp(signature, signature3, signaturelen) != 0)); @@ -1320,24 +1506,24 @@ void test_ecdsa_end_to_end(void) { CHECK((signaturelen4 != signaturelen2) || (memcmp(signature4, signature2, signaturelen4) != 0)); CHECK((signaturelen4 != signaturelen) || (memcmp(signature4, signature, signaturelen4) != 0)); /* Verify. */ - CHECK(secp256k1_ecdsa_verify(message, signature, signaturelen, pubkey, pubkeylen) == 1); - CHECK(secp256k1_ecdsa_verify(message, signature2, signaturelen2, pubkey, pubkeylen) == 1); - CHECK(secp256k1_ecdsa_verify(message, signature3, signaturelen3, pubkey, pubkeylen) == 1); - CHECK(secp256k1_ecdsa_verify(message, signature4, signaturelen4, pubkey, pubkeylen) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, message, signature, signaturelen, pubkey, pubkeylen) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, message, signature2, signaturelen2, pubkey, pubkeylen) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, message, signature3, signaturelen3, pubkey, pubkeylen) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, message, signature4, signaturelen4, pubkey, pubkeylen) == 1); /* Destroy signature and verify again. */ signature[signaturelen - 1 - secp256k1_rand32() % 20] += 1 + (secp256k1_rand32() % 255); - CHECK(secp256k1_ecdsa_verify(message, signature, signaturelen, pubkey, pubkeylen) != 1); + CHECK(secp256k1_ecdsa_verify(ctx, message, signature, signaturelen, pubkey, pubkeylen) != 1); /* Compact sign. */ - CHECK(secp256k1_ecdsa_sign_compact(message, csignature, privkey, NULL, NULL, &recid) == 1); + CHECK(secp256k1_ecdsa_sign_compact(ctx, message, csignature, privkey, NULL, NULL, &recid) == 1); CHECK(!is_empty_compact_signature(csignature)); /* Recover. */ - CHECK(secp256k1_ecdsa_recover_compact(message, csignature, recpubkey, &recpubkeylen, pubkeylen == 33, recid) == 1); + CHECK(secp256k1_ecdsa_recover_compact(ctx, message, csignature, recpubkey, &recpubkeylen, pubkeylen == 33, recid) == 1); CHECK(recpubkeylen == pubkeylen); CHECK(memcmp(pubkey, recpubkey, pubkeylen) == 0); /* Destroy signature and verify again. */ csignature[secp256k1_rand32() % 64] += 1 + (secp256k1_rand32() % 255); - CHECK(secp256k1_ecdsa_recover_compact(message, csignature, recpubkey, &recpubkeylen, pubkeylen == 33, recid) != 1 || + CHECK(secp256k1_ecdsa_recover_compact(ctx, message, csignature, recpubkey, &recpubkeylen, pubkeylen == 33, recid) != 1 || memcmp(pubkey, recpubkey, pubkeylen) != 0); CHECK(recpubkeylen == pubkeylen); @@ -1351,7 +1537,9 @@ void test_random_pubkeys(void) { uint32_t r = secp256k1_rand32(); int len = (r & 3) == 0 ? 65 : 33; r>>=2; - if ((r & 3) == 0) len = (r & 252) >> 3; + if ((r & 3) == 0) { + len = (r & 252) >> 3; + } r>>=8; if (len == 65) { in[0] = (r & 2) ? 4 : (r & 1? 6 : 7); @@ -1359,10 +1547,16 @@ void test_random_pubkeys(void) { in[0] = (r & 1) ? 2 : 3; } r>>=2; - if ((r & 7) == 0) in[0] = (r & 2040) >> 3; + if ((r & 7) == 0) { + in[0] = (r & 2040) >> 3; + } r>>=11; - if (len > 1) secp256k1_rand256(&in[1]); - if (len > 33) secp256k1_rand256(&in[33]); + if (len > 1) { + secp256k1_rand256(&in[1]); + } + if (len > 33) { + secp256k1_rand256(&in[33]); + } if (secp256k1_eckey_pubkey_parse(&elem, in, len)) { unsigned char out[65]; unsigned char firstb; @@ -1374,7 +1568,9 @@ void test_random_pubkeys(void) { CHECK(size == len); CHECK(memcmp(&in[1], &out[1], len-1) == 0); /* ... except for the type of hybrid inputs. */ - if ((in[0] != 6) && (in[0] != 7)) CHECK(in[0] == out[0]); + if ((in[0] != 6) && (in[0] != 7)) { + CHECK(in[0] == out[0]); + } size = 65; CHECK(secp256k1_eckey_pubkey_serialize(&elem, in, &size, 0)); CHECK(size == 65); @@ -1384,8 +1580,11 @@ void test_random_pubkeys(void) { in[0] = (r & 1) ? 6 : 7; res = secp256k1_eckey_pubkey_parse(&elem2, in, size); if (firstb == 2 || firstb == 3) { - if (in[0] == firstb + 4) CHECK(res); - else CHECK(!res); + if (in[0] == firstb + 4) { + CHECK(res); + } else { + CHECK(!res); + } } if (res) { ge_equals_ge(&elem,&elem2); @@ -1447,10 +1646,10 @@ void test_ecdsa_edge_cases(void) { int pubkeyblen = 33; int recid; - CHECK(!secp256k1_ecdsa_recover_compact(msg32, sig64, pubkey, &pubkeylen, 0, 0)); - CHECK(secp256k1_ecdsa_recover_compact(msg32, sig64, pubkey, &pubkeylen, 0, 1)); - CHECK(!secp256k1_ecdsa_recover_compact(msg32, sig64, pubkey, &pubkeylen, 0, 2)); - CHECK(!secp256k1_ecdsa_recover_compact(msg32, sig64, pubkey, &pubkeylen, 0, 3)); + CHECK(!secp256k1_ecdsa_recover_compact(ctx, msg32, sig64, pubkey, &pubkeylen, 0, 0)); + CHECK(secp256k1_ecdsa_recover_compact(ctx, msg32, sig64, pubkey, &pubkeylen, 0, 1)); + CHECK(!secp256k1_ecdsa_recover_compact(ctx, msg32, sig64, pubkey, &pubkeylen, 0, 2)); + CHECK(!secp256k1_ecdsa_recover_compact(ctx, msg32, sig64, pubkey, &pubkeylen, 0, 3)); for (recid = 0; recid < 4; recid++) { int i; @@ -1495,42 +1694,44 @@ void test_ecdsa_edge_cases(void) { 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x45, 0x02, 0x01, 0x04 }; - CHECK(secp256k1_ecdsa_recover_compact(msg32, sigb64, pubkeyb, &pubkeyblen, 1, recid)); - CHECK(secp256k1_ecdsa_verify(msg32, sigbder, sizeof(sigbder), pubkeyb, pubkeyblen) == 1); + CHECK(secp256k1_ecdsa_recover_compact(ctx, msg32, sigb64, pubkeyb, &pubkeyblen, 1, recid)); + CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbder, sizeof(sigbder), pubkeyb, pubkeyblen) == 1); for (recid2 = 0; recid2 < 4; recid2++) { unsigned char pubkey2b[33]; int pubkey2blen = 33; - CHECK(secp256k1_ecdsa_recover_compact(msg32, sigb64, pubkey2b, &pubkey2blen, 1, recid2)); + CHECK(secp256k1_ecdsa_recover_compact(ctx, msg32, sigb64, pubkey2b, &pubkey2blen, 1, recid2)); /* Verifying with (order + r,4) should always fail. */ - CHECK(secp256k1_ecdsa_verify(msg32, sigbderlong, sizeof(sigbderlong), pubkey2b, pubkey2blen) != 1); + CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderlong, sizeof(sigbderlong), pubkey2b, pubkey2blen) != 1); } /* DER parsing tests. */ /* Zero length r/s. */ - CHECK(secp256k1_ecdsa_verify(msg32, sigcder_zr, sizeof(sigcder_zr), pubkeyb, pubkeyblen) == -2); - CHECK(secp256k1_ecdsa_verify(msg32, sigcder_zs, sizeof(sigcder_zs), pubkeyb, pubkeyblen) == -2); + CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigcder_zr, sizeof(sigcder_zr), pubkeyb, pubkeyblen) == -2); + CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigcder_zs, sizeof(sigcder_zs), pubkeyb, pubkeyblen) == -2); /* Leading zeros. */ - CHECK(secp256k1_ecdsa_verify(msg32, sigbderalt1, sizeof(sigbderalt1), pubkeyb, pubkeyblen) == 1); - CHECK(secp256k1_ecdsa_verify(msg32, sigbderalt2, sizeof(sigbderalt2), pubkeyb, pubkeyblen) == 1); - CHECK(secp256k1_ecdsa_verify(msg32, sigbderalt3, sizeof(sigbderalt3), pubkeyb, pubkeyblen) == 1); - CHECK(secp256k1_ecdsa_verify(msg32, sigbderalt4, sizeof(sigbderalt4), pubkeyb, pubkeyblen) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt1, sizeof(sigbderalt1), pubkeyb, pubkeyblen) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt2, sizeof(sigbderalt2), pubkeyb, pubkeyblen) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt3, sizeof(sigbderalt3), pubkeyb, pubkeyblen) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt4, sizeof(sigbderalt4), pubkeyb, pubkeyblen) == 1); sigbderalt3[4] = 1; - CHECK(secp256k1_ecdsa_verify(msg32, sigbderalt3, sizeof(sigbderalt3), pubkeyb, pubkeyblen) == -2); + CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt3, sizeof(sigbderalt3), pubkeyb, pubkeyblen) == -2); sigbderalt4[7] = 1; - CHECK(secp256k1_ecdsa_verify(msg32, sigbderalt4, sizeof(sigbderalt4), pubkeyb, pubkeyblen) == -2); + CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt4, sizeof(sigbderalt4), pubkeyb, pubkeyblen) == -2); /* Damage signature. */ sigbder[7]++; - CHECK(secp256k1_ecdsa_verify(msg32, sigbder, sizeof(sigbder), pubkeyb, pubkeyblen) == 0); + CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbder, sizeof(sigbder), pubkeyb, pubkeyblen) == 0); sigbder[7]--; - CHECK(secp256k1_ecdsa_verify(msg32, sigbder, 6, pubkeyb, pubkeyblen) == -2); - CHECK(secp256k1_ecdsa_verify(msg32, sigbder, sizeof(sigbder)-1, pubkeyb, pubkeyblen) == -2); + CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbder, 6, pubkeyb, pubkeyblen) == -2); + CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbder, sizeof(sigbder)-1, pubkeyb, pubkeyblen) == -2); for(i = 0; i < 8; i++) { int c; unsigned char orig = sigbder[i]; /*Try every single-byte change.*/ for (c = 0; c < 256; c++) { - if (c == orig ) continue; + if (c == orig ) { + continue; + } sigbder[i] = c; - CHECK(secp256k1_ecdsa_verify(msg32, sigbder, sizeof(sigbder), pubkeyb, pubkeyblen) == + CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbder, sizeof(sigbder), pubkeyb, pubkeyblen) == (i==4 || i==7) ? 0 : -2 ); } sigbder[i] = orig; @@ -1547,10 +1748,10 @@ void test_ecdsa_edge_cases(void) { secp256k1_scalar_negate(&sig.s, &sig.s); secp256k1_scalar_inverse(&sig.s, &sig.s); secp256k1_scalar_set_int(&sig.r, 1); - secp256k1_ecmult_gen(&keyj, &sig.r); + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &keyj, &sig.r); secp256k1_ge_set_gej(&key, &keyj); msg = sig.s; - CHECK(secp256k1_ecdsa_sig_verify(&sig, &key, &msg) == 0); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sig, &key, &msg) == 0); } /* Test r/s equal to zero */ @@ -1569,18 +1770,18 @@ void test_ecdsa_edge_cases(void) { }; unsigned char pubkeyc[65]; int pubkeyclen = 65; - CHECK(secp256k1_ecdsa_recover_compact(msg32, sigc64, pubkeyc, &pubkeyclen, 0, 0) == 1); - CHECK(secp256k1_ecdsa_verify(msg32, sigcder, sizeof(sigcder), pubkeyc, pubkeyclen) == 1); + CHECK(secp256k1_ecdsa_recover_compact(ctx, msg32, sigc64, pubkeyc, &pubkeyclen, 0, 0) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigcder, sizeof(sigcder), pubkeyc, pubkeyclen) == 1); sigcder[4] = 0; sigc64[31] = 0; - CHECK(secp256k1_ecdsa_recover_compact(msg32, sigc64, pubkeyb, &pubkeyblen, 1, 0) == 0); - CHECK(secp256k1_ecdsa_verify(msg32, sigcder, sizeof(sigcder), pubkeyc, pubkeyclen) == 0); + CHECK(secp256k1_ecdsa_recover_compact(ctx, msg32, sigc64, pubkeyb, &pubkeyblen, 1, 0) == 0); + CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigcder, sizeof(sigcder), pubkeyc, pubkeyclen) == 0); sigcder[4] = 1; sigcder[7] = 0; sigc64[31] = 1; sigc64[63] = 0; - CHECK(secp256k1_ecdsa_recover_compact(msg32, sigc64, pubkeyb, &pubkeyblen, 1, 0) == 0); - CHECK(secp256k1_ecdsa_verify(msg32, sigcder, sizeof(sigcder), pubkeyc, pubkeyclen) == 0); + CHECK(secp256k1_ecdsa_recover_compact(ctx, msg32, sigc64, pubkeyb, &pubkeyblen, 1, 0) == 0); + CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigcder, sizeof(sigcder), pubkeyc, pubkeyclen) == 0); } /*Signature where s would be zero.*/ @@ -1611,18 +1812,18 @@ void test_ecdsa_edge_cases(void) { }; unsigned char sig[72]; int siglen = 72; - CHECK(secp256k1_ecdsa_sign(msg, sig, &siglen, key, precomputed_nonce_function, nonce) == 0); + CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, precomputed_nonce_function, nonce) == 0); CHECK(siglen == 0); - CHECK(secp256k1_ecdsa_sign(msg, sig, &siglen, key, precomputed_nonce_function, nonce2) == 0); + CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, precomputed_nonce_function, nonce2) == 0); CHECK(siglen == 0); msg[31] = 0xaa; siglen = 72; - CHECK(secp256k1_ecdsa_sign(msg, sig, &siglen, key, precomputed_nonce_function, nonce) == 1); + CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, precomputed_nonce_function, nonce) == 1); CHECK(siglen > 0); - CHECK(secp256k1_ecdsa_sign(msg, sig, &siglen, key, precomputed_nonce_function, nonce2) == 1); + CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, precomputed_nonce_function, nonce2) == 1); CHECK(siglen > 0); siglen = 10; - CHECK(secp256k1_ecdsa_sign(msg, sig, &siglen, key, precomputed_nonce_function, nonce) != 1); + CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, precomputed_nonce_function, nonce) != 1); CHECK(siglen == 0); } @@ -1644,41 +1845,41 @@ void test_ecdsa_edge_cases(void) { msg[31] = 1; /* High key results in signature failure. */ memset(key, 0xFF, 32); - CHECK(secp256k1_ecdsa_sign(msg, sig, &siglen, key, NULL, extra) == 0); + CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, NULL, extra) == 0); CHECK(siglen == 0); /* Zero key results in signature failure. */ memset(key, 0, 32); - CHECK(secp256k1_ecdsa_sign(msg, sig, &siglen, key, NULL, extra) == 0); + CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, NULL, extra) == 0); CHECK(siglen == 0); /* Nonce function failure results in signature failure. */ key[31] = 1; - CHECK(secp256k1_ecdsa_sign(msg, sig, &siglen, key, nonce_function_test_fail, extra) == 0); + CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, nonce_function_test_fail, extra) == 0); CHECK(siglen == 0); - CHECK(secp256k1_ecdsa_sign_compact(msg, sig, key, nonce_function_test_fail, extra, &recid) == 0); + CHECK(secp256k1_ecdsa_sign_compact(ctx, msg, sig, key, nonce_function_test_fail, extra, &recid) == 0); CHECK(is_empty_compact_signature(sig)); /* The retry loop successfully makes its way to the first good value. */ siglen = 72; - CHECK(secp256k1_ecdsa_sign(msg, sig, &siglen, key, nonce_function_test_retry, extra) == 1); + CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, nonce_function_test_retry, extra) == 1); CHECK(siglen > 0); - CHECK(secp256k1_ecdsa_sign(msg, sig2, &siglen2, key, nonce_function_rfc6979, extra) == 1); + CHECK(secp256k1_ecdsa_sign(ctx, msg, sig2, &siglen2, key, nonce_function_rfc6979, extra) == 1); CHECK(siglen > 0); CHECK((siglen == siglen2) && (memcmp(sig, sig2, siglen) == 0)); - CHECK(secp256k1_ecdsa_sign_compact(msg, sig, key, nonce_function_test_retry, extra, &recid) == 1); + CHECK(secp256k1_ecdsa_sign_compact(ctx, msg, sig, key, nonce_function_test_retry, extra, &recid) == 1); CHECK(!is_empty_compact_signature(sig)); - CHECK(secp256k1_ecdsa_sign_compact(msg, sig2, key, nonce_function_rfc6979, extra, &recid2) == 1); + CHECK(secp256k1_ecdsa_sign_compact(ctx, msg, sig2, key, nonce_function_rfc6979, extra, &recid2) == 1); CHECK(!is_empty_compact_signature(sig2)); CHECK((recid == recid2) && (memcmp(sig, sig2, 64) == 0)); /* The default nonce function is determinstic. */ siglen = 72; siglen2 = 72; - CHECK(secp256k1_ecdsa_sign(msg, sig, &siglen, key, NULL, extra) == 1); + CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, NULL, extra) == 1); CHECK(siglen > 0); - CHECK(secp256k1_ecdsa_sign(msg, sig2, &siglen2, key, NULL, extra) == 1); + CHECK(secp256k1_ecdsa_sign(ctx, msg, sig2, &siglen2, key, NULL, extra) == 1); CHECK(siglen2 > 0); CHECK((siglen == siglen2) && (memcmp(sig, sig2, siglen) == 0)); - CHECK(secp256k1_ecdsa_sign_compact(msg, sig, key, NULL, extra, &recid) == 1); + CHECK(secp256k1_ecdsa_sign_compact(ctx, msg, sig, key, NULL, extra, &recid) == 1); CHECK(!is_empty_compact_signature(sig)); - CHECK(secp256k1_ecdsa_sign_compact(msg, sig2, key, NULL, extra, &recid2) == 1); + CHECK(secp256k1_ecdsa_sign_compact(ctx, msg, sig2, key, NULL, extra, &recid2) == 1); CHECK(!is_empty_compact_signature(sig)); CHECK((recid == recid2) && (memcmp(sig, sig2, 64) == 0)); /* The default nonce function changes output with different messages. */ @@ -1686,7 +1887,7 @@ void test_ecdsa_edge_cases(void) { int j; siglen2 = 72; msg[0] = i; - CHECK(secp256k1_ecdsa_sign(msg, sig2, &siglen2, key, NULL, extra) == 1); + CHECK(secp256k1_ecdsa_sign(ctx, msg, sig2, &siglen2, key, NULL, extra) == 1); CHECK(!is_empty_compact_signature(sig)); CHECK(secp256k1_ecdsa_sig_parse(&s[i], sig2, siglen2)); for (j = 0; j < i; j++) { @@ -1700,7 +1901,7 @@ void test_ecdsa_edge_cases(void) { int j; siglen2 = 72; key[0] = i - 256; - CHECK(secp256k1_ecdsa_sign(msg, sig2, &siglen2, key, NULL, extra) == 1); + CHECK(secp256k1_ecdsa_sign(ctx, msg, sig2, &siglen2, key, NULL, extra) == 1); CHECK(secp256k1_ecdsa_sig_parse(&s[i], sig2, siglen2)); for (j = 0; j < i; j++) { CHECK(!secp256k1_scalar_eq(&s[i].r, &s[j].r)); @@ -1719,8 +1920,8 @@ void test_ecdsa_edge_cases(void) { 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41, }; int outlen = 300; - CHECK(!secp256k1_ec_privkey_export(seckey, privkey, &outlen, 0)); - CHECK(!secp256k1_ec_privkey_export(seckey, privkey, &outlen, 1)); + CHECK(!secp256k1_ec_privkey_export(ctx, seckey, privkey, &outlen, 0)); + CHECK(!secp256k1_ec_privkey_export(ctx, seckey, privkey, &outlen, 1)); } } @@ -1735,7 +1936,7 @@ EC_KEY *get_openssl_key(const secp256k1_scalar_t *key) { const unsigned char* pbegin = privkey; int compr = secp256k1_rand32() & 1; EC_KEY *ec_key = EC_KEY_new_by_curve_name(NID_secp256k1); - CHECK(secp256k1_eckey_privkey_serialize(privkey, &privkeylen, key, compr)); + CHECK(secp256k1_eckey_privkey_serialize(&ctx->ecmult_gen_ctx, privkey, &privkeylen, key, compr)); CHECK(d2i_ECPrivateKey(&ec_key, &pbegin, privkeylen)); CHECK(EC_KEY_check_key(ec_key)); return ec_key; @@ -1756,16 +1957,16 @@ void test_ecdsa_openssl(void) { secp256k1_rand256_test(message); secp256k1_scalar_set_b32(&msg, message, NULL); random_scalar_order_test(&key); - secp256k1_ecmult_gen(&qj, &key); + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &qj, &key); secp256k1_ge_set_gej(&q, &qj); ec_key = get_openssl_key(&key); CHECK(ec_key); CHECK(ECDSA_sign(0, message, sizeof(message), signature, &sigsize, ec_key)); CHECK(secp256k1_ecdsa_sig_parse(&sig, signature, sigsize)); - CHECK(secp256k1_ecdsa_sig_verify(&sig, &q, &msg)); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sig, &q, &msg)); secp256k1_scalar_set_int(&one, 1); secp256k1_scalar_add(&msg2, &msg, &one); - CHECK(!secp256k1_ecdsa_sig_verify(&sig, &q, &msg2)); + CHECK(!secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sig, &q, &msg2)); random_sign(&sig, &key, &msg, NULL); CHECK(secp256k1_ecdsa_sig_serialize(signature, &secp_sigsize, &sig)); @@ -1825,10 +2026,13 @@ int main(int argc, char **argv) { printf("random seed = %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", seed16[0], seed16[1], seed16[2], seed16[3], seed16[4], seed16[5], seed16[6], seed16[7], seed16[8], seed16[9], seed16[10], seed16[11], seed16[12], seed16[13], seed16[14], seed16[15]); /* initialize */ - secp256k1_start(SECP256K1_START_SIGN | SECP256K1_START_VERIFY); + run_context_tests(); + ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); - /* initializing a second time shouldn't cause any harm or memory leaks. */ - secp256k1_start(SECP256K1_START_SIGN | SECP256K1_START_VERIFY); + if (secp256k1_rand32() & 1) { + secp256k1_rand256(run32); + CHECK(secp256k1_context_randomize(ctx, secp256k1_rand32() & 1 ? run32 : NULL)); + } run_sha256_tests(); run_hmac_sha256_tests(); @@ -1858,6 +2062,8 @@ int main(int argc, char **argv) { run_wnaf(); run_point_times_order(); run_ecmult_chain(); + run_ecmult_constants(); + run_ecmult_gen_blind(); /* ecdsa tests */ run_random_pubkeys(); @@ -1872,9 +2078,6 @@ int main(int argc, char **argv) { printf("random run = %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", run32[0], run32[1], run32[2], run32[3], run32[4], run32[5], run32[6], run32[7], run32[8], run32[9], run32[10], run32[11], run32[12], run32[13], run32[14], run32[15]); /* shutdown */ - secp256k1_stop(); - - /* shutting down twice shouldn't cause any double frees. */ - secp256k1_stop(); + secp256k1_context_destroy(ctx); return 0; } From a56054be650052361e8de79f0f03a56a043759e5 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Wed, 22 Apr 2015 14:28:26 -0700 Subject: [PATCH 2/2] Update key.cpp to use new libsecp256k1 libsecp256k1's API changed, so update key.cpp to use it. Libsecp256k1 now has explicit context objects, which makes it completely thread-safe. In turn, keep an explicit context object in key.cpp, which is explicitly initialized destroyed. This is not really pretty now, but it's more efficient than the static initialized object in key.cpp (which made for example bitcoin-tx slow, as for most of its calls, libsecp256k1 wasn't actually needed). This also brings in the new blinding support in libsecp256k1. By passing in a random seed, temporary variables during the elliptic curve computations are altered, in such a way that if an attacker does not know the blind, observing the internal operations leaks less information about the keys used. This was implemented by Greg Maxwell. --- src/bitcoin-tx.cpp | 13 ++++++++- src/init.cpp | 4 +++ src/key.cpp | 59 ++++++++++++++++++++++++--------------- src/key.h | 8 +++++- src/test/test_bitcoin.cpp | 3 ++ 5 files changed, 63 insertions(+), 24 deletions(-) diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp index 78f5c2c4b..f1cdc36b7 100644 --- a/src/bitcoin-tx.cpp +++ b/src/bitcoin-tx.cpp @@ -444,9 +444,18 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr) tx = mergedTx; } +class Secp256k1Init +{ +public: + Secp256k1Init() { ECC_Start(); } + ~Secp256k1Init() { ECC_Stop(); } +}; + static void MutateTx(CMutableTransaction& tx, const string& command, const string& commandVal) { + boost::scoped_ptr ecc; + if (command == "nversion") MutateTxVersion(tx, commandVal); else if (command == "locktime") @@ -464,8 +473,10 @@ static void MutateTx(CMutableTransaction& tx, const string& command, else if (command == "outscript") MutateTxAddOutScript(tx, commandVal); - else if (command == "sign") + else if (command == "sign") { + if (!ecc) { ecc.reset(new Secp256k1Init()); } MutateTxSign(tx, commandVal); + } else if (command == "load") RegisterLoad(commandVal); diff --git a/src/init.cpp b/src/init.cpp index 665aebe1c..854d8e94d 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -194,6 +194,7 @@ void Shutdown() delete pwalletMain; pwalletMain = NULL; #endif + ECC_Stop(); LogPrintf("%s: done\n", __func__); } @@ -788,6 +789,9 @@ bool AppInit2(boost::thread_group& threadGroup) // ********************************************************* Step 4: application initialization: dir lock, daemonize, pidfile, debug log + // Initialize elliptic curve code + ECC_Start(); + // Sanity check if (!InitSanityCheck()) return InitError(_("Initialization sanity check failed. Bitcoin Core is shutting down.")); diff --git a/src/key.cpp b/src/key.cpp index e146e47d0..49941d6c7 100644 --- a/src/key.cpp +++ b/src/key.cpp @@ -14,21 +14,7 @@ #include #include "ecwrapper.h" -//! anonymous namespace -namespace { - -class CSecp256k1Init { -public: - CSecp256k1Init() { - secp256k1_start(SECP256K1_START_SIGN); - } - ~CSecp256k1Init() { - secp256k1_stop(); - } -}; -static CSecp256k1Init instance_of_csecp256k1; - -} // anon namespace +static secp256k1_context_t* secp256k1_context = NULL; bool CKey::Check(const unsigned char *vch) { return eccrypto::Check(vch); @@ -44,7 +30,7 @@ void CKey::MakeNewKey(bool fCompressedIn) { } bool CKey::SetPrivKey(const CPrivKey &privkey, bool fCompressedIn) { - if (!secp256k1_ec_privkey_import((unsigned char*)begin(), &privkey[0], privkey.size())) + if (!secp256k1_ec_privkey_import(secp256k1_context, (unsigned char*)begin(), &privkey[0], privkey.size())) return false; fCompressed = fCompressedIn; fValid = true; @@ -57,7 +43,7 @@ CPrivKey CKey::GetPrivKey() const { int privkeylen, ret; privkey.resize(279); privkeylen = 279; - ret = secp256k1_ec_privkey_export(begin(), (unsigned char*)&privkey[0], &privkeylen, fCompressed); + ret = secp256k1_ec_privkey_export(secp256k1_context, begin(), (unsigned char*)&privkey[0], &privkeylen, fCompressed); assert(ret); privkey.resize(privkeylen); return privkey; @@ -67,7 +53,7 @@ CPubKey CKey::GetPubKey() const { assert(fValid); CPubKey result; int clen = 65; - int ret = secp256k1_ec_pubkey_create((unsigned char*)result.begin(), &clen, begin(), fCompressed); + int ret = secp256k1_ec_pubkey_create(secp256k1_context, (unsigned char*)result.begin(), &clen, begin(), fCompressed); assert((int)result.size() == clen); assert(ret); assert(result.IsValid()); @@ -81,7 +67,7 @@ bool CKey::Sign(const uint256 &hash, std::vector& vchSig, uint32_ int nSigLen = 72; unsigned char extra_entropy[32] = {0}; WriteLE32(extra_entropy, test_case); - int ret = secp256k1_ecdsa_sign(hash.begin(), (unsigned char*)&vchSig[0], &nSigLen, begin(), secp256k1_nonce_function_rfc6979, test_case ? extra_entropy : NULL); + int ret = secp256k1_ecdsa_sign(secp256k1_context, hash.begin(), (unsigned char*)&vchSig[0], &nSigLen, begin(), secp256k1_nonce_function_rfc6979, test_case ? extra_entropy : NULL); assert(ret); vchSig.resize(nSigLen); return true; @@ -106,7 +92,7 @@ bool CKey::SignCompact(const uint256 &hash, std::vector& vchSig) return false; vchSig.resize(65); int rec = -1; - int ret = secp256k1_ecdsa_sign_compact(hash.begin(), &vchSig[1], begin(), secp256k1_nonce_function_rfc6979, NULL, &rec); + int ret = secp256k1_ecdsa_sign_compact(secp256k1_context, hash.begin(), &vchSig[1], begin(), secp256k1_nonce_function_rfc6979, NULL, &rec); assert(ret); assert(rec != -1); vchSig[0] = 27 + rec + (fCompressed ? 4 : 0); @@ -114,7 +100,7 @@ bool CKey::SignCompact(const uint256 &hash, std::vector& vchSig) } bool CKey::Load(CPrivKey &privkey, CPubKey &vchPubKey, bool fSkipCheck=false) { - if (!secp256k1_ec_privkey_import((unsigned char*)begin(), &privkey[0], privkey.size())) + if (!secp256k1_ec_privkey_import(secp256k1_context, (unsigned char*)begin(), &privkey[0], privkey.size())) return false; fCompressed = vchPubKey.IsCompressed(); fValid = true; @@ -140,7 +126,7 @@ bool CKey::Derive(CKey& keyChild, unsigned char ccChild[32], unsigned int nChild } memcpy(ccChild, out+32, 32); memcpy((unsigned char*)keyChild.begin(), begin(), 32); - bool ret = secp256k1_ec_privkey_tweak_add((unsigned char*)keyChild.begin(), out); + bool ret = secp256k1_ec_privkey_tweak_add(secp256k1_context, (unsigned char*)keyChild.begin(), out); UnlockObject(out); keyChild.fCompressed = true; keyChild.fValid = ret; @@ -206,3 +192,32 @@ bool ECC_InitSanityCheck() { CPubKey pubkey = key.GetPubKey(); return key.VerifyPubKey(pubkey); } + + +void ECC_Start() { + assert(secp256k1_context == NULL); + + secp256k1_context_t *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); + assert(ctx != NULL); + + { + // Pass in a random blinding seed to the secp256k1 context. + unsigned char seed[32]; + LockObject(seed); + GetRandBytes(seed, 32); + bool ret = secp256k1_context_randomize(ctx, seed); + assert(ret); + UnlockObject(seed); + } + + secp256k1_context = ctx; +} + +void ECC_Stop() { + secp256k1_context_t *ctx = secp256k1_context; + secp256k1_context = NULL; + + if (ctx) { + secp256k1_context_destroy(ctx); + } +} diff --git a/src/key.h b/src/key.h index 104a8f5c7..89f316a14 100644 --- a/src/key.h +++ b/src/key.h @@ -173,7 +173,13 @@ struct CExtKey { void SetMaster(const unsigned char* seed, unsigned int nSeedLen); }; -/** Check that required EC support is available at runtime */ +/** Initialize the elliptic curve support. May not be called twice without calling ECC_Stop first. */ +void ECC_Start(void); + +/** Deinitialize the elliptic curve support. No-op if ECC_Start wasn't called first. */ +void ECC_Stop(void); + +/** Check that required EC support is available at runtime. */ bool ECC_InitSanityCheck(void); #endif // BITCOIN_KEY_H diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp index a2cb78c98..b0745d3da 100644 --- a/src/test/test_bitcoin.cpp +++ b/src/test/test_bitcoin.cpp @@ -6,6 +6,7 @@ #include "test_bitcoin.h" +#include "key.h" #include "main.h" #include "random.h" #include "txdb.h" @@ -28,6 +29,7 @@ extern void noui_connect(); BasicTestingSetup::BasicTestingSetup() { + ECC_Start(); SetupEnvironment(); fPrintToDebugLog = false; // don't want to write to debug.log file fCheckBlockIndex = true; @@ -35,6 +37,7 @@ BasicTestingSetup::BasicTestingSetup() } BasicTestingSetup::~BasicTestingSetup() { + ECC_Stop(); } TestingSetup::TestingSetup()