diff --git a/include/secp256k1.h b/include/secp256k1.h index 9de45f1f7d..b7ec6a2283 100644 --- a/include/secp256k1.h +++ b/include/secp256k1.h @@ -6,6 +6,7 @@ extern "C" { #endif #include +#include /** Unless explicitly stated all pointer arguments must not be NULL. * @@ -404,6 +405,46 @@ SECP256K1_API void secp256k1_context_set_error_callback( const void *data ) SECP256K1_ARG_NONNULL(1); +/** A pointer to a function implementing SHA256's internal compression function. + * + * This function processes one or more contiguous 64-byte message blocks and + * updates the internal SHA256 state accordingly. The function is not responsible + * for counting consumed blocks or bytes, nor for performing padding. + * + * In/Out: state: pointer to eight 32-bit words representing the current internal state; + * the state is updated in place. + * In: blocks64: pointer to concatenation of n_blocks blocks, of 64 bytes each. + * no alignment guarantees are made for this pointer. + * n_blocks: number of contiguous 64-byte blocks to process. + */ +typedef void (*secp256k1_sha256_compression_function)( + uint32_t *state, + const unsigned char *blocks64, + size_t n_blocks +); + +/** + * Set a callback function to override the internal SHA256 compression function. + * + * This installs a function to replace the built-in block-compression + * step used by the library's internal SHA256 implementation. + * The provided callback must exactly implement the effect of n_blocks + * repeated applications of the SHA256 compression function. + * + * This API exists to support environments that wish to route the + * SHA256 compression step through a hardware-accelerated or otherwise + * specialized implementation. It is NOT meant for replacing SHA256 + * with a different hash function. + * + * Args: ctx: pointer to a context object. + * In: fn_compression: pointer to a function implementing the compression function; + * passing NULL restores the default implementation. + */ +SECP256K1_API void secp256k1_context_set_sha256_compression( + secp256k1_context *ctx, + secp256k1_sha256_compression_function fn_compression +) SECP256K1_ARG_NONNULL(1); + /** Parse a variable-length public key into the pubkey object. * * Returns: 1 if the public key was fully valid. diff --git a/src/bench_ecmult.c b/src/bench_ecmult.c index bcf8b43153..c7c6aded3b 100644 --- a/src/bench_ecmult.c +++ b/src/bench_ecmult.c @@ -259,7 +259,7 @@ static void bench_ecmult_multi_teardown(void* arg, int iters) { } } -static void generate_scalar(uint32_t num, secp256k1_scalar* scalar) { +static void generate_scalar(const secp256k1_context *ctx, uint32_t num, secp256k1_scalar* scalar) { secp256k1_sha256 sha256; unsigned char c[10] = {'e', 'c', 'm', 'u', 'l', 't', 0, 0, 0, 0}; unsigned char buf[32]; @@ -269,8 +269,8 @@ static void generate_scalar(uint32_t num, secp256k1_scalar* scalar) { c[8] = num >> 16; c[9] = num >> 24; secp256k1_sha256_initialize(&sha256); - secp256k1_sha256_write(&sha256, c, sizeof(c)); - secp256k1_sha256_finalize(&sha256, buf); + secp256k1_sha256_write(secp256k1_get_hash_context(ctx), &sha256, c, sizeof(c)); + secp256k1_sha256_finalize(secp256k1_get_hash_context(ctx), &sha256, buf); secp256k1_scalar_set_b32(scalar, buf, &overflow); CHECK(!overflow); } @@ -362,7 +362,7 @@ int main(int argc, char **argv) { secp256k1_gej_set_ge(&data.pubkeys_gej[0], &secp256k1_ge_const_g); secp256k1_scalar_set_int(&data.seckeys[0], 1); for (i = 0; i < POINTS; ++i) { - generate_scalar(i, &data.scalars[i]); + generate_scalar(data.ctx, i, &data.scalars[i]); if (i) { secp256k1_gej_double_var(&data.pubkeys_gej[i], &data.pubkeys_gej[i - 1], NULL); secp256k1_scalar_add(&data.seckeys[i], &data.seckeys[i - 1], &data.seckeys[i - 1]); diff --git a/src/bench_internal.c b/src/bench_internal.c index 001bd25e08..44f8d2cba9 100644 --- a/src/bench_internal.c +++ b/src/bench_internal.c @@ -38,6 +38,7 @@ static void help(int default_iters) { } typedef struct { + const secp256k1_context* ctx; secp256k1_scalar scalar[2]; secp256k1_fe fe[4]; secp256k1_ge ge[2]; @@ -82,6 +83,9 @@ static void bench_setup(void* arg) { } }; + /* Customize context if needed */ + data->ctx = secp256k1_context_static; + secp256k1_scalar_set_b32(&data->scalar[0], init[0], NULL); secp256k1_scalar_set_b32(&data->scalar[1], init[1], NULL); secp256k1_fe_set_b32_limit(&data->fe[0], init[0]); @@ -344,11 +348,12 @@ static void bench_sha256(void* arg, int iters) { int i; bench_inv *data = (bench_inv*)arg; secp256k1_sha256 sha; + const secp256k1_hash_ctx *hash_ctx = secp256k1_get_hash_context(data->ctx); for (i = 0; i < iters; i++) { secp256k1_sha256_initialize(&sha); - secp256k1_sha256_write(&sha, data->data, 32); - secp256k1_sha256_finalize(&sha, data->data); + secp256k1_sha256_write(hash_ctx, &sha, data->data, 32); + secp256k1_sha256_finalize(hash_ctx, &sha, data->data); } } @@ -356,11 +361,12 @@ static void bench_hmac_sha256(void* arg, int iters) { int i; bench_inv *data = (bench_inv*)arg; secp256k1_hmac_sha256 hmac; + const secp256k1_hash_ctx *hash_ctx = secp256k1_get_hash_context(data->ctx); for (i = 0; i < iters; i++) { - secp256k1_hmac_sha256_initialize(&hmac, data->data, 32); - secp256k1_hmac_sha256_write(&hmac, data->data, 32); - secp256k1_hmac_sha256_finalize(&hmac, data->data); + secp256k1_hmac_sha256_initialize(hash_ctx, &hmac, data->data, 32); + secp256k1_hmac_sha256_write(hash_ctx, &hmac, data->data, 32); + secp256k1_hmac_sha256_finalize(hash_ctx, &hmac, data->data); } } @@ -368,10 +374,11 @@ static void bench_rfc6979_hmac_sha256(void* arg, int iters) { int i; bench_inv *data = (bench_inv*)arg; secp256k1_rfc6979_hmac_sha256 rng; + const secp256k1_hash_ctx *hash_ctx = secp256k1_get_hash_context(data->ctx); for (i = 0; i < iters; i++) { - secp256k1_rfc6979_hmac_sha256_initialize(&rng, data->data, 64); - secp256k1_rfc6979_hmac_sha256_generate(&rng, data->data, 32); + secp256k1_rfc6979_hmac_sha256_initialize(hash_ctx, &rng, data->data, 64); + secp256k1_rfc6979_hmac_sha256_generate(hash_ctx, &rng, data->data, 32); } } diff --git a/src/ecmult_gen.h b/src/ecmult_gen.h index 43dd10c38d..8bc4f14c31 100644 --- a/src/ecmult_gen.h +++ b/src/ecmult_gen.h @@ -7,6 +7,7 @@ #ifndef SECP256K1_ECMULT_GEN_H #define SECP256K1_ECMULT_GEN_H +#include "hash.h" #include "scalar.h" #include "group.h" @@ -132,12 +133,12 @@ typedef struct { secp256k1_fe proj_blind; } secp256k1_ecmult_gen_context; -static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context* ctx); +static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context* ctx, const secp256k1_hash_ctx *hash_ctx); static void secp256k1_ecmult_gen_context_clear(secp256k1_ecmult_gen_context* ctx); /** Multiply with the generator: R = a*G */ static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context* ctx, secp256k1_gej *r, const secp256k1_scalar *a); -static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const unsigned char *seed32); +static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const secp256k1_hash_ctx *hash_ctx, const unsigned char *seed32); #endif /* SECP256K1_ECMULT_GEN_H */ diff --git a/src/ecmult_gen_impl.h b/src/ecmult_gen_impl.h index 2159eed5e1..5a954977eb 100644 --- a/src/ecmult_gen_impl.h +++ b/src/ecmult_gen_impl.h @@ -14,8 +14,8 @@ #include "hash_impl.h" #include "precomputed_ecmult_gen.h" -static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context *ctx) { - secp256k1_ecmult_gen_blind(ctx, NULL); +static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context *ctx, const secp256k1_hash_ctx *hash_ctx) { + secp256k1_ecmult_gen_blind(ctx, hash_ctx, NULL); ctx->built = 1; } @@ -282,7 +282,7 @@ static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context *ctx, secp25 } /* Setup blinding values for secp256k1_ecmult_gen. */ -static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const unsigned char *seed32) { +static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const secp256k1_hash_ctx *hash_ctx, const unsigned char *seed32) { secp256k1_scalar b; secp256k1_scalar diff; secp256k1_gej gb; @@ -309,17 +309,17 @@ static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const */ VERIFY_CHECK(seed32 != NULL); memcpy(keydata + 32, seed32, 32); - secp256k1_rfc6979_hmac_sha256_initialize(&rng, keydata, 64); + secp256k1_rfc6979_hmac_sha256_initialize(hash_ctx, &rng, keydata, 64); secp256k1_memclear_explicit(keydata, sizeof(keydata)); /* Compute projective blinding factor (cannot be 0). */ - secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32); + secp256k1_rfc6979_hmac_sha256_generate(hash_ctx, &rng, nonce32, 32); secp256k1_fe_set_b32_mod(&f, nonce32); secp256k1_fe_cmov(&f, &secp256k1_fe_one, secp256k1_fe_normalizes_to_zero(&f)); ctx->proj_blind = f; /* For a random blinding value b, set scalar_offset=diff-b, ge_offset=bG */ - secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32); + secp256k1_rfc6979_hmac_sha256_generate(hash_ctx, &rng, nonce32, 32); secp256k1_scalar_set_b32(&b, nonce32, NULL); /* The blinding value cannot be zero, as that would mean ge_offset = infinity, * which secp256k1_gej_add_ge cannot handle. */ diff --git a/src/hash.h b/src/hash.h index 43cdd60c3f..79d97671e5 100644 --- a/src/hash.h +++ b/src/hash.h @@ -10,6 +10,12 @@ #include #include +typedef struct { + secp256k1_sha256_compression_function fn_sha256_compression; +} secp256k1_hash_ctx; + +static void secp256k1_hash_ctx_init(secp256k1_hash_ctx *hash_ctx); + typedef struct { uint32_t s[8]; unsigned char buf[64]; @@ -21,17 +27,17 @@ static void secp256k1_sha256_initialize(secp256k1_sha256 *hash); * The byte counter must be a multiple of 64, i.e., there must be no unwritten * bytes in the buffer. */ static void secp256k1_sha256_initialize_midstate(secp256k1_sha256 *hash, uint64_t bytes, const uint32_t state[8]); -static void secp256k1_sha256_write(secp256k1_sha256 *hash, const unsigned char *data, size_t size); -static void secp256k1_sha256_finalize(secp256k1_sha256 *hash, unsigned char *out32); +static void secp256k1_sha256_write(const secp256k1_hash_ctx *hash_ctx, secp256k1_sha256 *hash, const unsigned char *data, size_t size); +static void secp256k1_sha256_finalize(const secp256k1_hash_ctx *hash_ctx, secp256k1_sha256 *hash, unsigned char *out32); static void secp256k1_sha256_clear(secp256k1_sha256 *hash); typedef struct { secp256k1_sha256 inner, outer; } secp256k1_hmac_sha256; -static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256 *hash, const unsigned char *key, size_t size); -static void secp256k1_hmac_sha256_write(secp256k1_hmac_sha256 *hash, const unsigned char *data, size_t size); -static void secp256k1_hmac_sha256_finalize(secp256k1_hmac_sha256 *hash, unsigned char *out32); +static void secp256k1_hmac_sha256_initialize(const secp256k1_hash_ctx *hash_ctx, secp256k1_hmac_sha256 *hash, const unsigned char *key, size_t size); +static void secp256k1_hmac_sha256_write(const secp256k1_hash_ctx *hash_ctx, secp256k1_hmac_sha256 *hash, const unsigned char *data, size_t size); +static void secp256k1_hmac_sha256_finalize(const secp256k1_hash_ctx *hash_ctx, secp256k1_hmac_sha256 *hash, unsigned char *out32); static void secp256k1_hmac_sha256_clear(secp256k1_hmac_sha256 *hash); typedef struct { @@ -40,8 +46,8 @@ typedef struct { int retry; } secp256k1_rfc6979_hmac_sha256; -static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256 *rng, const unsigned char *key, size_t keylen); -static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256 *rng, unsigned char *out, size_t outlen); +static void secp256k1_rfc6979_hmac_sha256_initialize(const secp256k1_hash_ctx *hash_ctx, secp256k1_rfc6979_hmac_sha256 *rng, const unsigned char *key, size_t keylen); +static void secp256k1_rfc6979_hmac_sha256_generate(const secp256k1_hash_ctx *hash_ctx, secp256k1_rfc6979_hmac_sha256 *rng, unsigned char *out, size_t outlen); static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256 *rng); static void secp256k1_rfc6979_hmac_sha256_clear(secp256k1_rfc6979_hmac_sha256 *rng); diff --git a/src/hash_impl.h b/src/hash_impl.h index da3b466095..7c40f82e76 100644 --- a/src/hash_impl.h +++ b/src/hash_impl.h @@ -48,7 +48,7 @@ static void secp256k1_sha256_initialize_midstate(secp256k1_sha256 *hash, uint64_ } /** Perform one SHA-256 transformation, processing 16 big endian 32-bit words. */ -static void secp256k1_sha256_transform(uint32_t* s, const unsigned char* buf) { +static void secp256k1_sha256_transform_impl(uint32_t* s, const unsigned char* buf) { uint32_t a = s[0], b = s[1], c = s[2], d = s[3], e = s[4], f = s[5], g = s[6], h = s[7]; uint32_t w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14, w15; @@ -130,26 +130,52 @@ static void secp256k1_sha256_transform(uint32_t* s, const unsigned char* buf) { s[7] += h; } -static void secp256k1_sha256_write(secp256k1_sha256 *hash, const unsigned char *data, size_t len) { +static void secp256k1_sha256_transform(uint32_t *state, const unsigned char *blocks64, size_t n_blocks) { + while (n_blocks--) { + secp256k1_sha256_transform_impl(state, blocks64); + blocks64 += 64; + } +} + +static void secp256k1_hash_ctx_init(secp256k1_hash_ctx *hash_ctx) { + VERIFY_CHECK(hash_ctx != NULL); + hash_ctx->fn_sha256_compression = secp256k1_sha256_transform; +} + +static void secp256k1_sha256_write(const secp256k1_hash_ctx *hash_ctx, secp256k1_sha256 *hash, const unsigned char *data, size_t len) { + size_t chunk_len; size_t bufsize = hash->bytes & 0x3F; hash->bytes += len; VERIFY_CHECK(hash->bytes >= len); - while (len >= 64 - bufsize) { - /* Fill the buffer, and process it. */ - size_t chunk_len = 64 - bufsize; + VERIFY_CHECK(hash_ctx != NULL); + VERIFY_CHECK(hash_ctx->fn_sha256_compression != NULL); + + /* If we exceed the 64-byte block size with this input, process it and wipe the buffer */ + chunk_len = 64 - bufsize; + if (bufsize && len >= chunk_len) { memcpy(hash->buf + bufsize, data, chunk_len); data += chunk_len; len -= chunk_len; - secp256k1_sha256_transform(hash->s, hash->buf); + hash_ctx->fn_sha256_compression(hash->s, hash->buf, 1); bufsize = 0; } + + /* If we still have data to process, invoke compression directly on the input */ + if (len >= 64) { + const size_t n_blocks = len / 64; + const size_t advance = n_blocks * 64; + hash_ctx->fn_sha256_compression(hash->s, data, n_blocks); + data += advance; + len -= advance; + } + + /* Fill the buffer with what remains */ if (len) { - /* Fill the buffer with what remains. */ memcpy(hash->buf + bufsize, data, len); } } -static void secp256k1_sha256_finalize(secp256k1_sha256 *hash, unsigned char *out32) { +static void secp256k1_sha256_finalize(const secp256k1_hash_ctx *hash_ctx, secp256k1_sha256 *hash, unsigned char *out32) { static const unsigned char pad[64] = {0x80}; unsigned char sizedesc[8]; int i; @@ -157,8 +183,8 @@ static void secp256k1_sha256_finalize(secp256k1_sha256 *hash, unsigned char *out VERIFY_CHECK(hash->bytes < ((uint64_t)1 << 61)); secp256k1_write_be32(&sizedesc[0], hash->bytes >> 29); secp256k1_write_be32(&sizedesc[4], hash->bytes << 3); - secp256k1_sha256_write(hash, pad, 1 + ((119 - (hash->bytes % 64)) % 64)); - secp256k1_sha256_write(hash, sizedesc, 8); + secp256k1_sha256_write(hash_ctx, hash, pad, 1 + ((119 - (hash->bytes % 64)) % 64)); + secp256k1_sha256_write(hash_ctx, hash, sizedesc, 8); for (i = 0; i < 8; i++) { secp256k1_write_be32(&out32[4*i], hash->s[i]); hash->s[i] = 0; @@ -167,22 +193,22 @@ static void secp256k1_sha256_finalize(secp256k1_sha256 *hash, unsigned char *out /* Initializes a sha256 struct and writes the 64 byte string * SHA256(tag)||SHA256(tag) into it. */ -static void secp256k1_sha256_initialize_tagged(secp256k1_sha256 *hash, const unsigned char *tag, size_t taglen) { +static void secp256k1_sha256_initialize_tagged(const secp256k1_hash_ctx *hash_ctx, secp256k1_sha256 *hash, const unsigned char *tag, size_t taglen) { unsigned char buf[32]; secp256k1_sha256_initialize(hash); - secp256k1_sha256_write(hash, tag, taglen); - secp256k1_sha256_finalize(hash, buf); + secp256k1_sha256_write(hash_ctx, hash, tag, taglen); + secp256k1_sha256_finalize(hash_ctx, hash, buf); secp256k1_sha256_initialize(hash); - secp256k1_sha256_write(hash, buf, 32); - secp256k1_sha256_write(hash, buf, 32); + secp256k1_sha256_write(hash_ctx, hash, buf, 32); + secp256k1_sha256_write(hash_ctx, hash, buf, 32); } static void secp256k1_sha256_clear(secp256k1_sha256 *hash) { secp256k1_memclear_explicit(hash, sizeof(*hash)); } -static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256 *hash, const unsigned char *key, size_t keylen) { +static void secp256k1_hmac_sha256_initialize(const secp256k1_hash_ctx *hash_ctx, secp256k1_hmac_sha256 *hash, const unsigned char *key, size_t keylen) { size_t n; unsigned char rkey[64]; if (keylen <= sizeof(rkey)) { @@ -191,8 +217,8 @@ static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256 *hash, const } else { secp256k1_sha256 sha256; secp256k1_sha256_initialize(&sha256); - secp256k1_sha256_write(&sha256, key, keylen); - secp256k1_sha256_finalize(&sha256, rkey); + secp256k1_sha256_write(hash_ctx, &sha256, key, keylen); + secp256k1_sha256_finalize(hash_ctx, &sha256, rkey); memset(rkey + 32, 0, 32); } @@ -200,33 +226,33 @@ static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256 *hash, const for (n = 0; n < sizeof(rkey); n++) { rkey[n] ^= 0x5c; } - secp256k1_sha256_write(&hash->outer, rkey, sizeof(rkey)); + secp256k1_sha256_write(hash_ctx, &hash->outer, rkey, sizeof(rkey)); secp256k1_sha256_initialize(&hash->inner); for (n = 0; n < sizeof(rkey); n++) { rkey[n] ^= 0x5c ^ 0x36; } - secp256k1_sha256_write(&hash->inner, rkey, sizeof(rkey)); + secp256k1_sha256_write(hash_ctx, &hash->inner, rkey, sizeof(rkey)); secp256k1_memclear_explicit(rkey, sizeof(rkey)); } -static void secp256k1_hmac_sha256_write(secp256k1_hmac_sha256 *hash, const unsigned char *data, size_t size) { - secp256k1_sha256_write(&hash->inner, data, size); +static void secp256k1_hmac_sha256_write(const secp256k1_hash_ctx *hash_ctx, secp256k1_hmac_sha256 *hash, const unsigned char *data, size_t size) { + secp256k1_sha256_write(hash_ctx, &hash->inner, data, size); } -static void secp256k1_hmac_sha256_finalize(secp256k1_hmac_sha256 *hash, unsigned char *out32) { +static void secp256k1_hmac_sha256_finalize(const secp256k1_hash_ctx *hash_ctx, secp256k1_hmac_sha256 *hash, unsigned char *out32) { unsigned char temp[32]; - secp256k1_sha256_finalize(&hash->inner, temp); - secp256k1_sha256_write(&hash->outer, temp, 32); + secp256k1_sha256_finalize(hash_ctx, &hash->inner, temp); + secp256k1_sha256_write(hash_ctx, &hash->outer, temp, 32); secp256k1_memclear_explicit(temp, sizeof(temp)); - secp256k1_sha256_finalize(&hash->outer, out32); + secp256k1_sha256_finalize(hash_ctx, &hash->outer, out32); } static void secp256k1_hmac_sha256_clear(secp256k1_hmac_sha256 *hash) { secp256k1_memclear_explicit(hash, sizeof(*hash)); } -static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256 *rng, const unsigned char *key, size_t keylen) { +static void secp256k1_rfc6979_hmac_sha256_initialize(const secp256k1_hash_ctx *hash_ctx, secp256k1_rfc6979_hmac_sha256 *rng, const unsigned char *key, size_t keylen) { secp256k1_hmac_sha256 hmac; static const unsigned char zero[1] = {0x00}; static const unsigned char one[1] = {0x01}; @@ -235,47 +261,47 @@ static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha2 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_finalize(&hmac, rng->k); - secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); - secp256k1_hmac_sha256_write(&hmac, rng->v, 32); - secp256k1_hmac_sha256_finalize(&hmac, rng->v); + secp256k1_hmac_sha256_initialize(hash_ctx, &hmac, rng->k, 32); + secp256k1_hmac_sha256_write(hash_ctx, &hmac, rng->v, 32); + secp256k1_hmac_sha256_write(hash_ctx, &hmac, zero, 1); + secp256k1_hmac_sha256_write(hash_ctx, &hmac, key, keylen); + secp256k1_hmac_sha256_finalize(hash_ctx, &hmac, rng->k); + secp256k1_hmac_sha256_initialize(hash_ctx, &hmac, rng->k, 32); + secp256k1_hmac_sha256_write(hash_ctx, &hmac, rng->v, 32); + secp256k1_hmac_sha256_finalize(hash_ctx, &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_finalize(&hmac, rng->k); - secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); - secp256k1_hmac_sha256_write(&hmac, rng->v, 32); - secp256k1_hmac_sha256_finalize(&hmac, rng->v); + secp256k1_hmac_sha256_initialize(hash_ctx, &hmac, rng->k, 32); + secp256k1_hmac_sha256_write(hash_ctx, &hmac, rng->v, 32); + secp256k1_hmac_sha256_write(hash_ctx, &hmac, one, 1); + secp256k1_hmac_sha256_write(hash_ctx, &hmac, key, keylen); + secp256k1_hmac_sha256_finalize(hash_ctx, &hmac, rng->k); + secp256k1_hmac_sha256_initialize(hash_ctx, &hmac, rng->k, 32); + secp256k1_hmac_sha256_write(hash_ctx, &hmac, rng->v, 32); + secp256k1_hmac_sha256_finalize(hash_ctx, &hmac, rng->v); rng->retry = 0; } -static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256 *rng, unsigned char *out, size_t outlen) { +static void secp256k1_rfc6979_hmac_sha256_generate(const secp256k1_hash_ctx *hash_ctx, secp256k1_rfc6979_hmac_sha256 *rng, unsigned char *out, size_t outlen) { /* RFC6979 3.2.h. */ static const unsigned char zero[1] = {0x00}; if (rng->retry) { secp256k1_hmac_sha256 hmac; - 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_finalize(&hmac, rng->k); - secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); - secp256k1_hmac_sha256_write(&hmac, rng->v, 32); - secp256k1_hmac_sha256_finalize(&hmac, rng->v); + secp256k1_hmac_sha256_initialize(hash_ctx, &hmac, rng->k, 32); + secp256k1_hmac_sha256_write(hash_ctx, &hmac, rng->v, 32); + secp256k1_hmac_sha256_write(hash_ctx, &hmac, zero, 1); + secp256k1_hmac_sha256_finalize(hash_ctx, &hmac, rng->k); + secp256k1_hmac_sha256_initialize(hash_ctx, &hmac, rng->k, 32); + secp256k1_hmac_sha256_write(hash_ctx, &hmac, rng->v, 32); + secp256k1_hmac_sha256_finalize(hash_ctx, &hmac, rng->v); } while (outlen > 0) { secp256k1_hmac_sha256 hmac; size_t now = outlen; - secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); - secp256k1_hmac_sha256_write(&hmac, rng->v, 32); - secp256k1_hmac_sha256_finalize(&hmac, rng->v); + secp256k1_hmac_sha256_initialize(hash_ctx, &hmac, rng->k, 32); + secp256k1_hmac_sha256_write(hash_ctx, &hmac, rng->v, 32); + secp256k1_hmac_sha256_finalize(hash_ctx, &hmac, rng->v); if (now > 32) { now = 32; } diff --git a/src/modules/ecdh/main_impl.h b/src/modules/ecdh/main_impl.h index 9f2dfdd56a..b0359b2c41 100644 --- a/src/modules/ecdh/main_impl.h +++ b/src/modules/ecdh/main_impl.h @@ -10,20 +10,24 @@ #include "../../../include/secp256k1_ecdh.h" #include "../../ecmult_const_impl.h" -static int ecdh_hash_function_sha256(unsigned char *output, const unsigned char *x32, const unsigned char *y32, void *data) { +static int ecdh_hash_function_sha256_impl(const secp256k1_hash_ctx *hash_ctx, unsigned char *output, const unsigned char *x32, const unsigned char *y32, void *data) { unsigned char version = (y32[31] & 0x01) | 0x02; secp256k1_sha256 sha; (void)data; secp256k1_sha256_initialize(&sha); - secp256k1_sha256_write(&sha, &version, 1); - secp256k1_sha256_write(&sha, x32, 32); - secp256k1_sha256_finalize(&sha, output); + secp256k1_sha256_write(hash_ctx, &sha, &version, 1); + secp256k1_sha256_write(hash_ctx, &sha, x32, 32); + secp256k1_sha256_finalize(hash_ctx, &sha, output); secp256k1_sha256_clear(&sha); return 1; } +static int ecdh_hash_function_sha256(unsigned char *output, const unsigned char *x32, const unsigned char *y32, void *data) { + return ecdh_hash_function_sha256_impl(secp256k1_get_hash_context(secp256k1_context_static), output, x32, y32, data); +} + const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_sha256 = ecdh_hash_function_sha256; const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_default = ecdh_hash_function_sha256; @@ -41,10 +45,6 @@ int secp256k1_ecdh(const secp256k1_context* ctx, unsigned char *output, const se ARG_CHECK(point != NULL); ARG_CHECK(scalar != NULL); - if (hashfp == NULL) { - hashfp = secp256k1_ecdh_hash_function_default; - } - secp256k1_pubkey_load(ctx, &pt, point); secp256k1_scalar_set_b32(&s, scalar, &overflow); @@ -60,7 +60,12 @@ int secp256k1_ecdh(const secp256k1_context* ctx, unsigned char *output, const se secp256k1_fe_get_b32(x, &pt.x); secp256k1_fe_get_b32(y, &pt.y); - ret = hashfp(output, x, y, data); + if (hashfp == NULL) { + /* Use ctx-aware function by default */ + ret = ecdh_hash_function_sha256_impl(secp256k1_get_hash_context(ctx), output, x, y, data); + } else { + ret = hashfp(output, x, y, data); + } secp256k1_memclear_explicit(x, sizeof(x)); secp256k1_memclear_explicit(y, sizeof(y)); diff --git a/src/modules/ecdh/tests_impl.h b/src/modules/ecdh/tests_impl.h index cb1d953d2a..c75ce9ff67 100644 --- a/src/modules/ecdh/tests_impl.h +++ b/src/modules/ecdh/tests_impl.h @@ -8,6 +8,7 @@ #define SECP256K1_MODULE_ECDH_TESTS_H #include "../../unit_test.h" +#include "../../testutil.h" static int ecdh_hash_function_test_xpassthru(unsigned char *output, const unsigned char *x, const unsigned char *y, void *data) { (void)y; @@ -83,13 +84,37 @@ static void test_ecdh_generator_basepoint(void) { /* compute "explicitly" */ CHECK(secp256k1_ec_pubkey_serialize(CTX, point_ser, &point_ser_len, &point[1], SECP256K1_EC_COMPRESSED) == 1); secp256k1_sha256_initialize(&sha); - secp256k1_sha256_write(&sha, point_ser, point_ser_len); - secp256k1_sha256_finalize(&sha, output_ser); + secp256k1_sha256_write(secp256k1_get_hash_context(CTX), &sha, point_ser, point_ser_len); + secp256k1_sha256_finalize(secp256k1_get_hash_context(CTX), &sha, output_ser); /* compare */ CHECK(secp256k1_memcmp_var(output_ecdh, output_ser, 32) == 0); } } +DEFINE_SHA256_TRANSFORM_PROBE(sha256_ecdh) +static void test_ecdh_ctx_sha256(void) { + /* Check ctx-provided SHA256 compression override takes effect */ + secp256k1_context *ctx = secp256k1_context_clone(CTX); + unsigned char out_default[65], out_custom[65]; + const unsigned char sk[32] = {1}; + secp256k1_pubkey pubkey; + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, sk) == 1); + + /* Default behavior */ + CHECK(secp256k1_ecdh(ctx, out_default, &pubkey, sk, NULL, NULL) == 1); + CHECK(!sha256_ecdh_called); + + /* Override SHA256 compression directly, bypassing the ctx setter sanity checks */ + ctx->hash_ctx.fn_sha256_compression = sha256_ecdh; + CHECK(secp256k1_ecdh(ctx, out_custom, &pubkey, sk, NULL, NULL) == 1); + + /* Outputs must differ if custom compression was used */ + CHECK(secp256k1_memcmp_var(out_default, out_custom, 32) != 0); + CHECK(sha256_ecdh_called); + + secp256k1_context_destroy(ctx); +} + static void test_bad_scalar(void) { unsigned char s_zero[32] = { 0 }; unsigned char s_overflow[32] = { 0 }; @@ -187,6 +212,7 @@ static const struct tf_test_entry tests_ecdh[] = { CASE1(test_bad_scalar), CASE1(test_result_basepoint), CASE1(test_ecdh_wycheproof), + CASE1(test_ecdh_ctx_sha256), }; #endif /* SECP256K1_MODULE_ECDH_TESTS_H */ diff --git a/src/modules/ellswift/main_impl.h b/src/modules/ellswift/main_impl.h index f9ef0ac86c..27cb3db65e 100644 --- a/src/modules/ellswift/main_impl.h +++ b/src/modules/ellswift/main_impl.h @@ -307,7 +307,7 @@ static int secp256k1_ellswift_xswiftec_inv_var(secp256k1_fe *t, const secp256k1_ * hasher is a SHA256 object to which an incrementing 4-byte counter is written to generate randomness. * Writing 13 bytes (4 bytes for counter, plus 9 bytes for the SHA256 padding) cannot cross a * 64-byte block size boundary (to make sure it only triggers a single SHA256 compression). */ -static void secp256k1_ellswift_prng(unsigned char* out32, const secp256k1_sha256 *hasher, uint32_t cnt) { +static void secp256k1_ellswift_prng(const secp256k1_hash_ctx *hash_ctx, unsigned char* out32, const secp256k1_sha256 *hasher, uint32_t cnt) { secp256k1_sha256 hash = *hasher; unsigned char buf4[4]; #ifdef VERIFY @@ -317,8 +317,8 @@ static void secp256k1_ellswift_prng(unsigned char* out32, const secp256k1_sha256 buf4[1] = cnt >> 8; buf4[2] = cnt >> 16; buf4[3] = cnt >> 24; - secp256k1_sha256_write(&hash, buf4, 4); - secp256k1_sha256_finalize(&hash, out32); + secp256k1_sha256_write(hash_ctx, &hash, buf4, 4); + secp256k1_sha256_finalize(hash_ctx, &hash, out32); /* Writing and finalizing together should trigger exactly one SHA256 compression. */ VERIFY_CHECK(((hash.bytes) >> 6) == (blocks + 1)); @@ -330,7 +330,7 @@ static void secp256k1_ellswift_prng(unsigned char* out32, const secp256k1_sha256 * needs encoding. * * hasher is a hasher in the secp256k1_ellswift_prng sense, with the same restrictions. */ -static void secp256k1_ellswift_xelligatorswift_var(unsigned char *u32, secp256k1_fe *t, const secp256k1_fe *x, const secp256k1_sha256 *hasher) { +static void secp256k1_ellswift_xelligatorswift_var(const secp256k1_context *ctx, unsigned char *u32, secp256k1_fe *t, const secp256k1_fe *x, const secp256k1_sha256 *hasher) { /* Pool of 3-bit branch values. */ unsigned char branch_hash[32]; /* Number of 3-bit values in branch_hash left. */ @@ -346,14 +346,14 @@ static void secp256k1_ellswift_xelligatorswift_var(unsigned char *u32, secp256k1 secp256k1_fe u; /* If the pool of branch values is empty, populate it. */ if (branches_left == 0) { - secp256k1_ellswift_prng(branch_hash, hasher, cnt++); + secp256k1_ellswift_prng(secp256k1_get_hash_context(ctx), branch_hash, hasher, cnt++); branches_left = 64; } /* Take a 3-bit branch value from the branch pool (top bit is discarded). */ --branches_left; branch = (branch_hash[branches_left >> 1] >> ((branches_left & 1) << 2)) & 7; /* Compute a new u value by hashing. */ - secp256k1_ellswift_prng(u32, hasher, cnt++); + secp256k1_ellswift_prng(secp256k1_get_hash_context(ctx), u32, hasher, cnt++); /* overflow is not a problem (we prefer uniform u32 over uniform u). */ secp256k1_fe_set_b32_mod(&u, u32); /* Since u is the output of a hash, it should practically never be 0. We could apply the @@ -372,8 +372,8 @@ static void secp256k1_ellswift_xelligatorswift_var(unsigned char *u32, secp256k1 * as input, and returns an encoding that matches the provided Y coordinate rather than a random * one. */ -static void secp256k1_ellswift_elligatorswift_var(unsigned char *u32, secp256k1_fe *t, const secp256k1_ge *p, const secp256k1_sha256 *hasher) { - secp256k1_ellswift_xelligatorswift_var(u32, t, &p->x, hasher); +static void secp256k1_ellswift_elligatorswift_var(const secp256k1_context *ctx, unsigned char *u32, secp256k1_fe *t, const secp256k1_ge *p, const secp256k1_sha256 *hasher) { + secp256k1_ellswift_xelligatorswift_var(ctx, u32, t, &p->x, hasher); secp256k1_fe_normalize_var(t); if (secp256k1_fe_is_odd(t) != secp256k1_fe_is_odd(&p->y)) { secp256k1_fe_negate(t, t, 1); @@ -406,11 +406,11 @@ int secp256k1_ellswift_encode(const secp256k1_context *ctx, unsigned char *ell64 * BIP340 tagged hash with tag "secp256k1_ellswift_encode". */ secp256k1_ellswift_sha256_init_encode(&hash); secp256k1_eckey_pubkey_serialize33(&p, p64); - secp256k1_sha256_write(&hash, p64, sizeof(p64)); - secp256k1_sha256_write(&hash, rnd32, 32); + secp256k1_sha256_write(secp256k1_get_hash_context(ctx), &hash, p64, sizeof(p64)); + secp256k1_sha256_write(secp256k1_get_hash_context(ctx), &hash, rnd32, 32); /* Compute ElligatorSwift encoding and construct output. */ - secp256k1_ellswift_elligatorswift_var(ell64, &t, &p, &hash); /* puts u in ell64[0..32] */ + secp256k1_ellswift_elligatorswift_var(ctx, ell64, &t, &p, &hash); /* puts u in ell64[0..32] */ secp256k1_fe_get_b32(ell64 + 32, &t); /* puts t in ell64[32..64] */ return 1; } @@ -452,13 +452,13 @@ int secp256k1_ellswift_create(const secp256k1_context *ctx, unsigned char *ell64 /* Set up hasher state. The used RNG is H(privkey || "\x00"*32 [|| auxrnd32] || cnt++), * using BIP340 tagged hash with tag "secp256k1_ellswift_create". */ secp256k1_ellswift_sha256_init_create(&hash); - secp256k1_sha256_write(&hash, seckey32, 32); - secp256k1_sha256_write(&hash, zero32, sizeof(zero32)); + secp256k1_sha256_write(secp256k1_get_hash_context(ctx), &hash, seckey32, 32); + secp256k1_sha256_write(secp256k1_get_hash_context(ctx), &hash, zero32, sizeof(zero32)); secp256k1_declassify(ctx, &hash, sizeof(hash)); /* private key is hashed now */ - if (auxrnd32) secp256k1_sha256_write(&hash, auxrnd32, 32); + if (auxrnd32) secp256k1_sha256_write(secp256k1_get_hash_context(ctx), &hash, auxrnd32, 32); /* Compute ElligatorSwift encoding and construct output. */ - secp256k1_ellswift_elligatorswift_var(ell64, &t, &p, &hash); /* puts u in ell64[0..32] */ + secp256k1_ellswift_elligatorswift_var(ctx, ell64, &t, &p, &hash); /* puts u in ell64[0..32] */ secp256k1_fe_get_b32(ell64 + 32, &t); /* puts t in ell64[32..64] */ secp256k1_memczero(ell64, 64, !ret); @@ -482,20 +482,24 @@ int secp256k1_ellswift_decode(const secp256k1_context *ctx, secp256k1_pubkey *pu return 1; } -static int ellswift_xdh_hash_function_prefix(unsigned char *output, const unsigned char *x32, const unsigned char *ell_a64, const unsigned char *ell_b64, void *data) { +static int ellswift_xdh_hash_function_prefix_impl(const secp256k1_hash_ctx *hash_ctx, unsigned char *output, const unsigned char *x32, const unsigned char *ell_a64, const unsigned char *ell_b64, void *data) { secp256k1_sha256 sha; secp256k1_sha256_initialize(&sha); - secp256k1_sha256_write(&sha, data, 64); - secp256k1_sha256_write(&sha, ell_a64, 64); - secp256k1_sha256_write(&sha, ell_b64, 64); - secp256k1_sha256_write(&sha, x32, 32); - secp256k1_sha256_finalize(&sha, output); + secp256k1_sha256_write(hash_ctx, &sha, data, 64); + secp256k1_sha256_write(hash_ctx, &sha, ell_a64, 64); + secp256k1_sha256_write(hash_ctx, &sha, ell_b64, 64); + secp256k1_sha256_write(hash_ctx, &sha, x32, 32); + secp256k1_sha256_finalize(hash_ctx, &sha, output); secp256k1_sha256_clear(&sha); return 1; } +static int ellswift_xdh_hash_function_prefix(unsigned char *output, const unsigned char *x32, const unsigned char *ell_a64, const unsigned char *ell_b64, void *data) { + return ellswift_xdh_hash_function_prefix_impl(secp256k1_get_hash_context(secp256k1_context_static), output, x32, ell_a64, ell_b64, data); +} + /** Set hash state to the BIP340 tagged hash midstate for "bip324_ellswift_xonly_ecdh". */ static void secp256k1_ellswift_sha256_init_bip324(secp256k1_sha256* hash) { static const uint32_t midstate[8] = { @@ -505,21 +509,25 @@ static void secp256k1_ellswift_sha256_init_bip324(secp256k1_sha256* hash) { secp256k1_sha256_initialize_midstate(hash, 64, midstate); } -static int ellswift_xdh_hash_function_bip324(unsigned char* output, const unsigned char *x32, const unsigned char *ell_a64, const unsigned char *ell_b64, void *data) { +static int ellswift_xdh_hash_function_bip324_impl(const secp256k1_hash_ctx *hash_ctx, unsigned char* output, const unsigned char *x32, const unsigned char *ell_a64, const unsigned char *ell_b64, void *data) { secp256k1_sha256 sha; (void)data; secp256k1_ellswift_sha256_init_bip324(&sha); - secp256k1_sha256_write(&sha, ell_a64, 64); - secp256k1_sha256_write(&sha, ell_b64, 64); - secp256k1_sha256_write(&sha, x32, 32); - secp256k1_sha256_finalize(&sha, output); + secp256k1_sha256_write(hash_ctx, &sha, ell_a64, 64); + secp256k1_sha256_write(hash_ctx, &sha, ell_b64, 64); + secp256k1_sha256_write(hash_ctx, &sha, x32, 32); + secp256k1_sha256_finalize(hash_ctx, &sha, output); secp256k1_sha256_clear(&sha); return 1; } +static int ellswift_xdh_hash_function_bip324(unsigned char* output, const unsigned char *x32, const unsigned char *ell_a64, const unsigned char *ell_b64, void *data) { + return ellswift_xdh_hash_function_bip324_impl(secp256k1_get_hash_context(secp256k1_context_static), output, x32, ell_a64, ell_b64, data); +} + const secp256k1_ellswift_xdh_hash_function secp256k1_ellswift_xdh_hash_function_prefix = ellswift_xdh_hash_function_prefix; const secp256k1_ellswift_xdh_hash_function secp256k1_ellswift_xdh_hash_function_bip324 = ellswift_xdh_hash_function_bip324; @@ -554,8 +562,14 @@ int secp256k1_ellswift_xdh(const secp256k1_context *ctx, unsigned char *output, secp256k1_fe_normalize(&px); secp256k1_fe_get_b32(sx, &px); - /* Invoke hasher */ - ret = hashfp(output, sx, ell_a64, ell_b64, data); + /* Invoke hasher. Use ctx-aware function by default */ + if (hashfp == secp256k1_ellswift_xdh_hash_function_bip324) { + ret = ellswift_xdh_hash_function_bip324_impl(secp256k1_get_hash_context(ctx), output, sx, ell_a64, ell_b64, data); + } else if (hashfp == secp256k1_ellswift_xdh_hash_function_prefix) { + ret = ellswift_xdh_hash_function_prefix_impl(secp256k1_get_hash_context(ctx), output, sx, ell_a64, ell_b64, data); + } else { + ret = hashfp(output, sx, ell_a64, ell_b64, data); + } secp256k1_memclear_explicit(sx, sizeof(sx)); secp256k1_fe_clear(&px); diff --git a/src/modules/ellswift/tests_impl.h b/src/modules/ellswift/tests_impl.h index e309041127..a849c8e833 100644 --- a/src/modules/ellswift/tests_impl.h +++ b/src/modules/ellswift/tests_impl.h @@ -431,9 +431,44 @@ void ellswift_xdh_correctness_tests(void) { } } +DEFINE_SHA256_TRANSFORM_PROBE(sha256_ellswift_xdh) +void ellswift_xdh_ctx_sha256_tests(void) { + /* Check ctx-provided SHA256 compression override takes effect */ + secp256k1_context *ctx = secp256k1_context_clone(CTX); + unsigned char out_default[65], out_custom[65]; + const unsigned char skA[32] = {1}, skB[32] = {2}; + unsigned char keyA[64], keyB[64], data[64] = {0}; + const secp256k1_ellswift_xdh_hash_function hash_funcs[2] = {secp256k1_ellswift_xdh_hash_function_bip324, secp256k1_ellswift_xdh_hash_function_prefix}; + int i; + + CHECK(secp256k1_ellswift_create(ctx, keyA, skA, NULL)); + CHECK(secp256k1_ellswift_create(ctx, keyB, skB, NULL)); + + for (i = 0; i < 2; i++) { + const secp256k1_ellswift_xdh_hash_function hash_fn = hash_funcs[i]; + /* Default behavior. No ctx-provided SHA256 compression */ + CHECK(secp256k1_ellswift_xdh(ctx, out_default, keyA, keyB, skA, 0, hash_fn, data)); + CHECK(!sha256_ellswift_xdh_called); + + /* Override SHA256 compression directly, bypassing the ctx setter sanity checks */ + ctx->hash_ctx.fn_sha256_compression = sha256_ellswift_xdh; + CHECK(secp256k1_ellswift_xdh(ctx, out_custom, keyA, keyB, skA, 0, hash_fn, data)); + CHECK(sha256_ellswift_xdh_called); + /* Outputs must differ if custom compression was used */ + CHECK(secp256k1_memcmp_var(out_default, out_custom, 32) != 0); + + /* Restore defaults */ + sha256_ellswift_xdh_called = 0; + secp256k1_context_set_sha256_compression(ctx, NULL); + } + + secp256k1_context_destroy(ctx); +} + /* Test hash initializers */ void ellswift_hash_init_tests(void) { secp256k1_sha256 sha_optimized; + const secp256k1_hash_ctx *hash_ctx = secp256k1_get_hash_context(CTX); /* "secp256k1_ellswift_encode" */ static const unsigned char encode_tag[] = {'s', 'e', 'c', 'p', '2', '5', '6', 'k', '1', '_', 'e', 'l', 'l', 's', 'w', 'i', 'f', 't', '_', 'e', 'n', 'c', 'o', 'd', 'e'}; /* "secp256k1_ellswift_create" */ @@ -445,19 +480,19 @@ void ellswift_hash_init_tests(void) { * secp256k1_ellswift_sha256_init_encode has the expected * state. */ secp256k1_ellswift_sha256_init_encode(&sha_optimized); - test_sha256_tag_midstate(&sha_optimized, encode_tag, sizeof(encode_tag)); + test_sha256_tag_midstate(hash_ctx, &sha_optimized, encode_tag, sizeof(encode_tag)); /* Check that hash initialized by * secp256k1_ellswift_sha256_init_create has the expected * state. */ secp256k1_ellswift_sha256_init_create(&sha_optimized); - test_sha256_tag_midstate(&sha_optimized, create_tag, sizeof(create_tag)); + test_sha256_tag_midstate(hash_ctx, &sha_optimized, create_tag, sizeof(create_tag)); /* Check that hash initialized by * secp256k1_ellswift_sha256_init_bip324 has the expected * state. */ secp256k1_ellswift_sha256_init_bip324(&sha_optimized); - test_sha256_tag_midstate(&sha_optimized, bip324_tag, sizeof(bip324_tag)); + test_sha256_tag_midstate(hash_ctx, &sha_optimized, bip324_tag, sizeof(bip324_tag)); } void ellswift_xdh_bad_scalar_tests(void) { @@ -498,6 +533,7 @@ static const struct tf_test_entry tests_ellswift[] = { CASE1(ellswift_xdh_correctness_tests), CASE1(ellswift_hash_init_tests), CASE1(ellswift_xdh_bad_scalar_tests), + CASE1(ellswift_xdh_ctx_sha256_tests), }; #endif diff --git a/src/modules/musig/keyagg.h b/src/modules/musig/keyagg.h index a0b37252f8..30e77aa951 100644 --- a/src/modules/musig/keyagg.h +++ b/src/modules/musig/keyagg.h @@ -27,6 +27,6 @@ typedef struct { static int secp256k1_keyagg_cache_load(const secp256k1_context* ctx, secp256k1_keyagg_cache_internal *cache_i, const secp256k1_musig_keyagg_cache *cache); -static void secp256k1_musig_keyaggcoef(secp256k1_scalar *r, const secp256k1_keyagg_cache_internal *cache_i, secp256k1_ge *pk); +static void secp256k1_musig_keyaggcoef(const secp256k1_hash_ctx *hash_ctx, secp256k1_scalar *r, const secp256k1_keyagg_cache_internal *cache_i, secp256k1_ge *pk); #endif diff --git a/src/modules/musig/keyagg_impl.h b/src/modules/musig/keyagg_impl.h index 4eb48ddc87..f67245d56d 100644 --- a/src/modules/musig/keyagg_impl.h +++ b/src/modules/musig/keyagg_impl.h @@ -82,9 +82,9 @@ static int secp256k1_musig_compute_pks_hash(const secp256k1_context *ctx, unsign return 0; } VERIFY_CHECK(ser_len == sizeof(ser)); - secp256k1_sha256_write(&sha, ser, sizeof(ser)); + secp256k1_sha256_write(secp256k1_get_hash_context(ctx), &sha, ser, sizeof(ser)); } - secp256k1_sha256_finalize(&sha, pks_hash); + secp256k1_sha256_finalize(secp256k1_get_hash_context(ctx), &sha, pks_hash); return 1; } @@ -103,7 +103,7 @@ static void secp256k1_musig_keyaggcoef_sha256(secp256k1_sha256 *sha) { * second_pk is the point at infinity in case there is no second_pk. Assumes * that pk is not the point at infinity and that the Y-coordinates of pk and * second_pk are normalized. */ -static void secp256k1_musig_keyaggcoef_internal(secp256k1_scalar *r, const unsigned char *pks_hash, secp256k1_ge *pk, const secp256k1_ge *second_pk) { +static void secp256k1_musig_keyaggcoef_internal(const secp256k1_hash_ctx *hash_ctx, secp256k1_scalar *r, const unsigned char *pks_hash, secp256k1_ge *pk, const secp256k1_ge *second_pk) { VERIFY_CHECK(!secp256k1_ge_is_infinity(pk)); if (!secp256k1_ge_is_infinity(second_pk) @@ -113,20 +113,20 @@ static void secp256k1_musig_keyaggcoef_internal(secp256k1_scalar *r, const unsig secp256k1_sha256 sha; unsigned char buf[33]; secp256k1_musig_keyaggcoef_sha256(&sha); - secp256k1_sha256_write(&sha, pks_hash, 32); + secp256k1_sha256_write(hash_ctx, &sha, pks_hash, 32); /* Serialization does not fail since the pk is not the point at infinity * (according to this function's precondition). */ secp256k1_eckey_pubkey_serialize33(pk, buf); - secp256k1_sha256_write(&sha, buf, sizeof(buf)); - secp256k1_sha256_finalize(&sha, buf); + secp256k1_sha256_write(hash_ctx, &sha, buf, sizeof(buf)); + secp256k1_sha256_finalize(hash_ctx, &sha, buf); secp256k1_scalar_set_b32(r, buf, NULL); } } /* Assumes that pk is not the point at infinity and that the Y-coordinates of pk * and cache_i->second_pk are normalized. */ -static void secp256k1_musig_keyaggcoef(secp256k1_scalar *r, const secp256k1_keyagg_cache_internal *cache_i, secp256k1_ge *pk) { - secp256k1_musig_keyaggcoef_internal(r, cache_i->pks_hash, pk, &cache_i->second_pk); +static void secp256k1_musig_keyaggcoef(const secp256k1_hash_ctx *hash_ctx, secp256k1_scalar *r, const secp256k1_keyagg_cache_internal *cache_i, secp256k1_ge *pk) { + secp256k1_musig_keyaggcoef_internal(hash_ctx, r, cache_i->pks_hash, pk, &cache_i->second_pk); } typedef struct { @@ -149,7 +149,7 @@ static int secp256k1_musig_pubkey_agg_callback(secp256k1_scalar *sc, secp256k1_g #else (void) ret; #endif - secp256k1_musig_keyaggcoef_internal(sc, ctx->pks_hash, pt, &ctx->second_pk); + secp256k1_musig_keyaggcoef_internal(secp256k1_get_hash_context(ctx->ctx), sc, ctx->pks_hash, pt, &ctx->second_pk); return 1; } diff --git a/src/modules/musig/session_impl.h b/src/modules/musig/session_impl.h index 42fcd81e12..6a37bfdf8e 100644 --- a/src/modules/musig/session_impl.h +++ b/src/modules/musig/session_impl.h @@ -289,20 +289,20 @@ int secp256k1_musig_partial_sig_serialize(const secp256k1_context* ctx, unsigned } /* Write optional inputs into the hash */ -static void secp256k1_nonce_function_musig_helper(secp256k1_sha256 *sha, unsigned int prefix_size, const unsigned char *data, unsigned char len) { +static void secp256k1_nonce_function_musig_helper(const secp256k1_hash_ctx *hash_ctx, secp256k1_sha256 *sha, unsigned int prefix_size, const unsigned char *data, unsigned char len) { unsigned char zero[7] = { 0 }; /* The spec requires length prefixes to be between 1 and 8 bytes * (inclusive) */ VERIFY_CHECK(prefix_size >= 1 && prefix_size <= 8); /* Since the length of all input data fits in a byte, we can always pad the * length prefix with prefix_size - 1 zero bytes. */ - secp256k1_sha256_write(sha, zero, prefix_size - 1); + secp256k1_sha256_write(hash_ctx, sha, zero, prefix_size - 1); if (data != NULL) { - secp256k1_sha256_write(sha, &len, 1); - secp256k1_sha256_write(sha, data, len); + secp256k1_sha256_write(hash_ctx, sha, &len, 1); + secp256k1_sha256_write(hash_ctx, sha, data, len); } else { len = 0; - secp256k1_sha256_write(sha, &len, 1); + secp256k1_sha256_write(hash_ctx, sha, &len, 1); } } @@ -326,7 +326,7 @@ static void secp256k1_nonce_function_musig_sha256_tagged(secp256k1_sha256 *sha) secp256k1_sha256_initialize_midstate(sha, 64, midstate); } -static void secp256k1_nonce_function_musig(secp256k1_scalar *k, const unsigned char *session_secrand, const unsigned char *msg32, const unsigned char *seckey32, const unsigned char *pk33, const unsigned char *agg_pk32, const unsigned char *extra_input32) { +static void secp256k1_nonce_function_musig(const secp256k1_hash_ctx *hash_ctx, secp256k1_scalar *k, const unsigned char *session_secrand, const unsigned char *msg32, const unsigned char *seckey32, const unsigned char *pk33, const unsigned char *agg_pk32, const unsigned char *extra_input32) { secp256k1_sha256 sha; unsigned char rand[32]; unsigned char i; @@ -334,8 +334,8 @@ static void secp256k1_nonce_function_musig(secp256k1_scalar *k, const unsigned c if (seckey32 != NULL) { secp256k1_nonce_function_musig_sha256_tagged_aux(&sha); - secp256k1_sha256_write(&sha, session_secrand, 32); - secp256k1_sha256_finalize(&sha, rand); + secp256k1_sha256_write(hash_ctx, &sha, session_secrand, 32); + secp256k1_sha256_finalize(hash_ctx, &sha, rand); for (i = 0; i < 32; i++) { rand[i] ^= seckey32[i]; } @@ -344,21 +344,21 @@ static void secp256k1_nonce_function_musig(secp256k1_scalar *k, const unsigned c } secp256k1_nonce_function_musig_sha256_tagged(&sha); - secp256k1_sha256_write(&sha, rand, sizeof(rand)); - secp256k1_nonce_function_musig_helper(&sha, 1, pk33, 33); - secp256k1_nonce_function_musig_helper(&sha, 1, agg_pk32, 32); + secp256k1_sha256_write(hash_ctx, &sha, rand, sizeof(rand)); + secp256k1_nonce_function_musig_helper(hash_ctx, &sha, 1, pk33, 33); + secp256k1_nonce_function_musig_helper(hash_ctx, &sha, 1, agg_pk32, 32); msg_present = msg32 != NULL; - secp256k1_sha256_write(&sha, &msg_present, 1); + secp256k1_sha256_write(hash_ctx, &sha, &msg_present, 1); if (msg_present) { - secp256k1_nonce_function_musig_helper(&sha, 8, msg32, 32); + secp256k1_nonce_function_musig_helper(hash_ctx, &sha, 8, msg32, 32); } - secp256k1_nonce_function_musig_helper(&sha, 4, extra_input32, 32); + secp256k1_nonce_function_musig_helper(hash_ctx, &sha, 4, extra_input32, 32); for (i = 0; i < 2; i++) { unsigned char buf[32]; secp256k1_sha256 sha_tmp = sha; - secp256k1_sha256_write(&sha_tmp, &i, 1); - secp256k1_sha256_finalize(&sha_tmp, buf); + secp256k1_sha256_write(hash_ctx, &sha_tmp, &i, 1); + secp256k1_sha256_finalize(hash_ctx, &sha_tmp, buf); secp256k1_scalar_set_b32(&k[i], buf, NULL); /* Attempt to erase secret data */ @@ -407,7 +407,7 @@ static int secp256k1_musig_nonce_gen_internal(const secp256k1_context* ctx, secp /* A pubkey cannot be the point at infinity */ secp256k1_eckey_pubkey_serialize33(&pk, pk_ser); - secp256k1_nonce_function_musig(k, input_nonce, msg32, seckey, pk_ser, aggpk_ser_ptr, extra_input32); + secp256k1_nonce_function_musig(secp256k1_get_hash_context(ctx), k, input_nonce, msg32, seckey, pk_ser, aggpk_ser_ptr, extra_input32); VERIFY_CHECK(!secp256k1_scalar_is_zero(&k[0])); VERIFY_CHECK(!secp256k1_scalar_is_zero(&k[1])); secp256k1_musig_secnonce_save(secnonce, k, &pk); @@ -541,7 +541,7 @@ static void secp256k1_musig_compute_noncehash_sha256_tagged(secp256k1_sha256 *sh } /* tagged_hash(aggnonce[0], aggnonce[1], agg_pk, msg) */ -static void secp256k1_musig_compute_noncehash(unsigned char *noncehash, secp256k1_ge *aggnonce, const unsigned char *agg_pk32, const unsigned char *msg) { +static void secp256k1_musig_compute_noncehash(const secp256k1_hash_ctx *hash_ctx, unsigned char *noncehash, secp256k1_ge *aggnonce, const unsigned char *agg_pk32, const unsigned char *msg) { unsigned char buf[33]; secp256k1_sha256 sha; int i; @@ -549,11 +549,11 @@ static void secp256k1_musig_compute_noncehash(unsigned char *noncehash, secp256k secp256k1_musig_compute_noncehash_sha256_tagged(&sha); for (i = 0; i < 2; i++) { secp256k1_musig_ge_serialize_ext(buf, &aggnonce[i]); - secp256k1_sha256_write(&sha, buf, sizeof(buf)); + secp256k1_sha256_write(hash_ctx, &sha, buf, sizeof(buf)); } - secp256k1_sha256_write(&sha, agg_pk32, 32); - secp256k1_sha256_write(&sha, msg, 32); - secp256k1_sha256_finalize(&sha, noncehash); + secp256k1_sha256_write(hash_ctx, &sha, agg_pk32, 32); + secp256k1_sha256_write(hash_ctx, &sha, msg, 32); + secp256k1_sha256_finalize(hash_ctx, &sha, noncehash); } /* out_nonce = nonce_pts[0] + b*nonce_pts[1] */ @@ -565,12 +565,12 @@ static void secp256k1_effective_nonce(secp256k1_gej *out_nonce, const secp256k1_ secp256k1_gej_add_ge_var(out_nonce, out_nonce, &nonce_pts[0], NULL); } -static void secp256k1_musig_nonce_process_internal(int *fin_nonce_parity, unsigned char *fin_nonce, secp256k1_scalar *b, secp256k1_ge *aggnonce_pts, const unsigned char *agg_pk32, const unsigned char *msg) { +static void secp256k1_musig_nonce_process_internal(const secp256k1_context *ctx, int *fin_nonce_parity, unsigned char *fin_nonce, secp256k1_scalar *b, secp256k1_ge *aggnonce_pts, const unsigned char *agg_pk32, const unsigned char *msg) { unsigned char noncehash[32]; secp256k1_ge fin_nonce_pt; secp256k1_gej fin_nonce_ptj; - secp256k1_musig_compute_noncehash(noncehash, aggnonce_pts, agg_pk32, msg); + secp256k1_musig_compute_noncehash(secp256k1_get_hash_context(ctx), noncehash, aggnonce_pts, agg_pk32, msg); secp256k1_scalar_set_b32(b, noncehash, NULL); /* fin_nonce = aggnonce_pts[0] + b*aggnonce_pts[1] */ secp256k1_effective_nonce(&fin_nonce_ptj, aggnonce_pts, b); @@ -607,8 +607,8 @@ int secp256k1_musig_nonce_process(const secp256k1_context* ctx, secp256k1_musig_ return 0; } - secp256k1_musig_nonce_process_internal(&session_i.fin_nonce_parity, fin_nonce, &session_i.noncecoef, aggnonce_pts, agg_pk32, msg32); - secp256k1_schnorrsig_challenge(&session_i.challenge, fin_nonce, msg32, 32, agg_pk32); + secp256k1_musig_nonce_process_internal(ctx, &session_i.fin_nonce_parity, fin_nonce, &session_i.noncecoef, aggnonce_pts, agg_pk32, msg32); + secp256k1_schnorrsig_challenge(secp256k1_get_hash_context(ctx), &session_i.challenge, fin_nonce, msg32, 32, agg_pk32); /* If there is a tweak then set `challenge` times `tweak` to the `s`-part.*/ secp256k1_scalar_set_int(&session_i.s_part, 0); @@ -678,7 +678,7 @@ int secp256k1_musig_partial_sign(const secp256k1_context* ctx, secp256k1_musig_p } /* Multiply KeyAgg coefficient */ - secp256k1_musig_keyaggcoef(&mu, &cache_i, &pk); + secp256k1_musig_keyaggcoef(secp256k1_get_hash_context(ctx), &mu, &cache_i, &pk); secp256k1_scalar_mul(&sk, &sk, &mu); if (!secp256k1_musig_session_load(ctx, &session_i, session)) { @@ -738,7 +738,7 @@ int secp256k1_musig_partial_sig_verify(const secp256k1_context* ctx, const secp2 /* Multiplying the challenge by the KeyAgg coefficient is equivalent * to multiplying the signer's public key by the coefficient, except * much easier to do. */ - secp256k1_musig_keyaggcoef(&mu, &cache_i, &pkp); + secp256k1_musig_keyaggcoef(secp256k1_get_hash_context(ctx), &mu, &cache_i, &pkp); secp256k1_scalar_mul(&e, &session_i.challenge, &mu); /* Negate e if secp256k1_fe_is_odd(&cache_i.pk.y)) XOR cache_i.parity_acc. diff --git a/src/modules/musig/tests_impl.h b/src/modules/musig/tests_impl.h index de09c5e280..cbeb1e285a 100644 --- a/src/modules/musig/tests_impl.h +++ b/src/modules/musig/tests_impl.h @@ -505,12 +505,12 @@ static void musig_api_tests(void) { CHECK(secp256k1_musig_partial_sig_agg(CTX, pre_sig, &session, partial_sig_ptr, 2) == 1); } -static void musig_nonce_bitflip(unsigned char **args, size_t n_flip, size_t n_bytes) { +static void musig_nonce_bitflip(const secp256k1_hash_ctx *hash_ctx, unsigned char **args, size_t n_flip, size_t n_bytes) { secp256k1_scalar k1[2], k2[2]; - secp256k1_nonce_function_musig(k1, args[0], args[1], args[2], args[3], args[4], args[5]); + secp256k1_nonce_function_musig(hash_ctx, k1, args[0], args[1], args[2], args[3], args[4], args[5]); testrand_flip(args[n_flip], n_bytes); - secp256k1_nonce_function_musig(k2, args[0], args[1], args[2], args[3], args[4], args[5]); + secp256k1_nonce_function_musig(hash_ctx, k2, args[0], args[1], args[2], args[3], args[4], args[5]); CHECK(secp256k1_scalar_eq(&k1[0], &k2[0]) == 0); CHECK(secp256k1_scalar_eq(&k1[1], &k2[1]) == 0); } @@ -526,6 +526,7 @@ static void musig_nonce_test(void) { int i, j; secp256k1_scalar k[6][2]; + const secp256k1_hash_ctx *hash_ctx = secp256k1_get_hash_context(CTX); testrand_bytes_test(session_secrand, sizeof(session_secrand)); testrand_bytes_test(sk, sizeof(sk)); testrand_bytes_test(pk, sizeof(pk)); @@ -541,12 +542,12 @@ static void musig_nonce_test(void) { args[4] = agg_pk; args[5] = extra_input; for (i = 0; i < COUNT; i++) { - musig_nonce_bitflip(args, 0, sizeof(session_secrand)); - musig_nonce_bitflip(args, 1, sizeof(msg)); - musig_nonce_bitflip(args, 2, sizeof(sk)); - musig_nonce_bitflip(args, 3, sizeof(pk)); - musig_nonce_bitflip(args, 4, sizeof(agg_pk)); - musig_nonce_bitflip(args, 5, sizeof(extra_input)); + musig_nonce_bitflip(hash_ctx, args, 0, sizeof(session_secrand)); + musig_nonce_bitflip(hash_ctx, args, 1, sizeof(msg)); + musig_nonce_bitflip(hash_ctx, args, 2, sizeof(sk)); + musig_nonce_bitflip(hash_ctx, args, 3, sizeof(pk)); + musig_nonce_bitflip(hash_ctx, args, 4, sizeof(agg_pk)); + musig_nonce_bitflip(hash_ctx, args, 5, sizeof(extra_input)); } /* Check that if any argument is NULL, a different nonce is produced than if * any other argument is NULL. */ @@ -555,12 +556,12 @@ static void musig_nonce_test(void) { memcpy(pk, session_secrand, sizeof(session_secrand)); memcpy(agg_pk, session_secrand, sizeof(agg_pk)); memcpy(extra_input, session_secrand, sizeof(extra_input)); - secp256k1_nonce_function_musig(k[0], args[0], args[1], args[2], args[3], args[4], args[5]); - secp256k1_nonce_function_musig(k[1], args[0], NULL, args[2], args[3], args[4], args[5]); - secp256k1_nonce_function_musig(k[2], args[0], args[1], NULL, args[3], args[4], args[5]); - secp256k1_nonce_function_musig(k[3], args[0], args[1], args[2], NULL, args[4], args[5]); - secp256k1_nonce_function_musig(k[4], args[0], args[1], args[2], args[3], NULL, args[5]); - secp256k1_nonce_function_musig(k[5], args[0], args[1], args[2], args[3], args[4], NULL); + secp256k1_nonce_function_musig(hash_ctx, k[0], args[0], args[1], args[2], args[3], args[4], args[5]); + secp256k1_nonce_function_musig(hash_ctx, k[1], args[0], NULL, args[2], args[3], args[4], args[5]); + secp256k1_nonce_function_musig(hash_ctx, k[2], args[0], args[1], NULL, args[3], args[4], args[5]); + secp256k1_nonce_function_musig(hash_ctx, k[3], args[0], args[1], args[2], NULL, args[4], args[5]); + secp256k1_nonce_function_musig(hash_ctx, k[4], args[0], args[1], args[2], args[3], NULL, args[5]); + secp256k1_nonce_function_musig(hash_ctx, k[5], args[0], args[1], args[2], args[3], args[4], NULL); for (i = 0; i < 6; i++) { CHECK(!secp256k1_scalar_eq(&k[i][0], &k[i][1])); for (j = i+1; j < 6; j++) { @@ -574,35 +575,36 @@ static void musig_nonce_test(void) { * state. */ static void sha256_tag_test(void) { secp256k1_sha256 sha; + const secp256k1_hash_ctx *hash_ctx = secp256k1_get_hash_context(CTX); { /* "KeyAgg list" */ static const unsigned char tag[] = {'K', 'e', 'y', 'A', 'g', 'g', ' ', 'l', 'i', 's', 't'}; secp256k1_musig_keyagglist_sha256(&sha); - test_sha256_tag_midstate(&sha, tag, sizeof(tag)); + test_sha256_tag_midstate(hash_ctx, &sha, tag, sizeof(tag)); } { /* "KeyAgg coefficient" */ static const unsigned char tag[] = {'K', 'e', 'y', 'A', 'g', 'g', ' ', 'c', 'o', 'e', 'f', 'f', 'i', 'c', 'i', 'e', 'n', 't'}; secp256k1_musig_keyaggcoef_sha256(&sha); - test_sha256_tag_midstate(&sha, tag, sizeof(tag)); + test_sha256_tag_midstate(hash_ctx, &sha, tag, sizeof(tag)); } { /* "MuSig/aux" */ static const unsigned char tag[] = { 'M', 'u', 'S', 'i', 'g', '/', 'a', 'u', 'x' }; secp256k1_nonce_function_musig_sha256_tagged_aux(&sha); - test_sha256_tag_midstate(&sha, tag, sizeof(tag)); + test_sha256_tag_midstate(hash_ctx, &sha, tag, sizeof(tag)); } { /* "MuSig/nonce" */ static const unsigned char tag[] = { 'M', 'u', 'S', 'i', 'g', '/', 'n', 'o', 'n', 'c', 'e' }; secp256k1_nonce_function_musig_sha256_tagged(&sha); - test_sha256_tag_midstate(&sha, tag, sizeof(tag)); + test_sha256_tag_midstate(hash_ctx, &sha, tag, sizeof(tag)); } { /* "MuSig/noncecoef" */ static const unsigned char tag[] = { 'M', 'u', 'S', 'i', 'g', '/', 'n', 'o', 'n', 'c', 'e', 'c', 'o', 'e', 'f' }; secp256k1_musig_compute_noncehash_sha256_tagged(&sha); - test_sha256_tag_midstate(&sha, tag, sizeof(tag)); + test_sha256_tag_midstate(hash_ctx, &sha, tag, sizeof(tag)); } } diff --git a/src/modules/schnorrsig/main_impl.h b/src/modules/schnorrsig/main_impl.h index 21c1f41298..5100557f4d 100644 --- a/src/modules/schnorrsig/main_impl.h +++ b/src/modules/schnorrsig/main_impl.h @@ -37,7 +37,7 @@ static const unsigned char bip340_algo[] = {'B', 'I', 'P', '0', '3', '4', '0', ' static const unsigned char schnorrsig_extraparams_magic[4] = SECP256K1_SCHNORRSIG_EXTRAPARAMS_MAGIC; -static int nonce_function_bip340(unsigned char *nonce32, const unsigned char *msg, size_t msglen, const unsigned char *key32, const unsigned char *xonly_pk32, const unsigned char *algo, size_t algolen, void *data) { +static int nonce_function_bip340_impl(const secp256k1_hash_ctx *hash_ctx, unsigned char *nonce32, const unsigned char *msg, size_t msglen, const unsigned char *key32, const unsigned char *xonly_pk32, const unsigned char *algo, size_t algolen, void *data) { secp256k1_sha256 sha; unsigned char masked_key[32]; int i; @@ -48,8 +48,8 @@ static int nonce_function_bip340(unsigned char *nonce32, const unsigned char *ms if (data != NULL) { secp256k1_nonce_function_bip340_sha256_tagged_aux(&sha); - secp256k1_sha256_write(&sha, data, 32); - secp256k1_sha256_finalize(&sha, masked_key); + secp256k1_sha256_write(hash_ctx, &sha, data, 32); + secp256k1_sha256_finalize(hash_ctx, &sha, masked_key); for (i = 0; i < 32; i++) { masked_key[i] ^= key32[i]; } @@ -73,20 +73,24 @@ static int nonce_function_bip340(unsigned char *nonce32, const unsigned char *ms && secp256k1_memcmp_var(algo, bip340_algo, algolen) == 0) { secp256k1_nonce_function_bip340_sha256_tagged(&sha); } else { - secp256k1_sha256_initialize_tagged(&sha, algo, algolen); + secp256k1_sha256_initialize_tagged(hash_ctx, &sha, algo, algolen); } /* Hash masked-key||pk||msg using the tagged hash as per the spec */ - secp256k1_sha256_write(&sha, masked_key, 32); - secp256k1_sha256_write(&sha, xonly_pk32, 32); - secp256k1_sha256_write(&sha, msg, msglen); - secp256k1_sha256_finalize(&sha, nonce32); + secp256k1_sha256_write(hash_ctx, &sha, masked_key, 32); + secp256k1_sha256_write(hash_ctx, &sha, xonly_pk32, 32); + secp256k1_sha256_write(hash_ctx, &sha, msg, msglen); + secp256k1_sha256_finalize(hash_ctx, &sha, nonce32); secp256k1_sha256_clear(&sha); secp256k1_memclear_explicit(masked_key, sizeof(masked_key)); return 1; } +static int nonce_function_bip340(unsigned char *nonce32, const unsigned char *msg, size_t msglen, const unsigned char *key32, const unsigned char *xonly_pk32, const unsigned char *algo, size_t algolen, void *data) { + return nonce_function_bip340_impl(secp256k1_get_hash_context(secp256k1_context_static), nonce32, msg, msglen, key32, xonly_pk32, algo, algolen, data); +} + const secp256k1_nonce_function_hardened secp256k1_nonce_function_bip340 = nonce_function_bip340; /* Initializes SHA256 with fixed midstate. This midstate was computed by applying @@ -99,17 +103,17 @@ static void secp256k1_schnorrsig_sha256_tagged(secp256k1_sha256 *sha) { secp256k1_sha256_initialize_midstate(sha, 64, midstate); } -static void secp256k1_schnorrsig_challenge(secp256k1_scalar* e, const unsigned char *r32, const unsigned char *msg, size_t msglen, const unsigned char *pubkey32) +static void secp256k1_schnorrsig_challenge(const secp256k1_hash_ctx *hash_ctx, secp256k1_scalar* e, const unsigned char *r32, const unsigned char *msg, size_t msglen, const unsigned char *pubkey32) { unsigned char buf[32]; secp256k1_sha256 sha; /* tagged hash(r.x, pk.x, msg) */ secp256k1_schnorrsig_sha256_tagged(&sha); - secp256k1_sha256_write(&sha, r32, 32); - secp256k1_sha256_write(&sha, pubkey32, 32); - secp256k1_sha256_write(&sha, msg, msglen); - secp256k1_sha256_finalize(&sha, buf); + secp256k1_sha256_write(hash_ctx, &sha, r32, 32); + secp256k1_sha256_write(hash_ctx, &sha, pubkey32, 32); + secp256k1_sha256_write(hash_ctx, &sha, msg, msglen); + secp256k1_sha256_finalize(hash_ctx, &sha, buf); /* Set scalar e to the challenge hash modulo the curve order as per * BIP340. */ secp256k1_scalar_set_b32(e, buf, NULL); @@ -133,10 +137,6 @@ static int secp256k1_schnorrsig_sign_internal(const secp256k1_context* ctx, unsi ARG_CHECK(msg != NULL || msglen == 0); ARG_CHECK(keypair != NULL); - if (noncefp == NULL) { - noncefp = secp256k1_nonce_function_bip340; - } - ret &= secp256k1_keypair_load(ctx, &sk, &pk, keypair); /* Because we are signing for a x-only pubkey, the secret key is negated * before signing if the point corresponding to the secret key does not @@ -147,7 +147,15 @@ static int secp256k1_schnorrsig_sign_internal(const secp256k1_context* ctx, unsi secp256k1_scalar_get_b32(seckey, &sk); secp256k1_fe_get_b32(pk_buf, &pk.x); - ret &= !!noncefp(nonce32, msg, msglen, seckey, pk_buf, bip340_algo, sizeof(bip340_algo), ndata); + + /* Compute nonce */ + if (noncefp == NULL || noncefp == secp256k1_nonce_function_bip340) { + /* Use context-aware nonce function by default */ + ret &= nonce_function_bip340_impl(secp256k1_get_hash_context(ctx), nonce32, msg, msglen, seckey, pk_buf, bip340_algo, sizeof(bip340_algo), ndata); + } else { + ret &= !!noncefp(nonce32, msg, msglen, seckey, pk_buf, bip340_algo, sizeof(bip340_algo), ndata); + } + secp256k1_scalar_set_b32(&k, nonce32, NULL); ret &= !secp256k1_scalar_is_zero(&k); secp256k1_scalar_cmov(&k, &secp256k1_scalar_one, !ret); @@ -165,7 +173,7 @@ static int secp256k1_schnorrsig_sign_internal(const secp256k1_context* ctx, unsi secp256k1_fe_normalize_var(&r.x); secp256k1_fe_get_b32(&sig64[0], &r.x); - secp256k1_schnorrsig_challenge(&e, &sig64[0], msg, msglen, pk_buf); + secp256k1_schnorrsig_challenge(secp256k1_get_hash_context(ctx), &e, &sig64[0], msg, msglen, pk_buf); secp256k1_scalar_mul(&e, &e, &sk); secp256k1_scalar_add(&e, &e, &k); secp256k1_scalar_get_b32(&sig64[32], &e); @@ -235,7 +243,7 @@ int secp256k1_schnorrsig_verify(const secp256k1_context* ctx, const unsigned cha /* Compute e. */ secp256k1_fe_get_b32(buf, &pk.x); - secp256k1_schnorrsig_challenge(&e, &sig64[0], msg, msglen, buf); + secp256k1_schnorrsig_challenge(secp256k1_get_hash_context(ctx), &e, &sig64[0], msg, msglen, buf); /* Compute rj = s*G + (-e)*pkj */ secp256k1_scalar_negate(&e, &e); diff --git a/src/modules/schnorrsig/tests_exhaustive_impl.h b/src/modules/schnorrsig/tests_exhaustive_impl.h index 601b54975d..a8298f65ba 100644 --- a/src/modules/schnorrsig/tests_exhaustive_impl.h +++ b/src/modules/schnorrsig/tests_exhaustive_impl.h @@ -105,7 +105,7 @@ static void test_exhaustive_schnorrsig_verify(const secp256k1_context *ctx, cons secp256k1_scalar e; unsigned char msg32[32]; testrand256(msg32); - secp256k1_schnorrsig_challenge(&e, sig64, msg32, sizeof(msg32), pk32); + secp256k1_schnorrsig_challenge(secp256k1_get_hash_context(ctx), &e, sig64, msg32, sizeof(msg32), pk32); /* Only do work if we hit a challenge we haven't tried before. */ if (!e_done[e]) { /* Iterate over the possible valid last 32 bytes in the signature. @@ -162,7 +162,7 @@ static void test_exhaustive_schnorrsig_sign(const secp256k1_context *ctx, unsign while (e_count_done < EXHAUSTIVE_TEST_ORDER) { secp256k1_scalar e; testrand256(msg32); - secp256k1_schnorrsig_challenge(&e, xonly_pubkey_bytes[k - 1], msg32, sizeof(msg32), xonly_pubkey_bytes[d - 1]); + secp256k1_schnorrsig_challenge(secp256k1_get_hash_context(ctx), &e, xonly_pubkey_bytes[k - 1], msg32, sizeof(msg32), xonly_pubkey_bytes[d - 1]); /* Only do work if we hit a challenge we haven't tried before. */ if (!e_done[e]) { secp256k1_scalar expected_s = (actual_k + e * actual_d) % EXHAUSTIVE_TEST_ORDER; diff --git a/src/modules/schnorrsig/tests_impl.h b/src/modules/schnorrsig/tests_impl.h index 9a1b15f0b2..56812e7f04 100644 --- a/src/modules/schnorrsig/tests_impl.h +++ b/src/modules/schnorrsig/tests_impl.h @@ -38,18 +38,20 @@ static void run_nonce_function_bip340_tests(void) { unsigned char *args[5]; int i; + const secp256k1_hash_ctx *hash_ctx = secp256k1_get_hash_context(CTX); + /* Check that hash initialized by * secp256k1_nonce_function_bip340_sha256_tagged has the expected * state. */ secp256k1_nonce_function_bip340_sha256_tagged(&sha_optimized); - test_sha256_tag_midstate(&sha_optimized, tag, sizeof(tag)); + test_sha256_tag_midstate(hash_ctx, &sha_optimized, tag, sizeof(tag)); /* Check that hash initialized by * secp256k1_nonce_function_bip340_sha256_tagged_aux has the expected * state. */ secp256k1_nonce_function_bip340_sha256_tagged_aux(&sha_optimized); - test_sha256_tag_midstate(&sha_optimized, aux_tag, sizeof(aux_tag)); + test_sha256_tag_midstate(hash_ctx, &sha_optimized, aux_tag, sizeof(aux_tag)); testrand256(msg); testrand256(key); @@ -162,8 +164,9 @@ static void test_schnorrsig_sha256_tagged(void) { unsigned char tag[] = {'B', 'I', 'P', '0', '3', '4', '0', '/', 'c', 'h', 'a', 'l', 'l', 'e', 'n', 'g', 'e'}; secp256k1_sha256 sha; secp256k1_sha256 sha_optimized; + const secp256k1_hash_ctx *hash_ctx = secp256k1_get_hash_context(CTX); - secp256k1_sha256_initialize_tagged(&sha, (unsigned char *) tag, sizeof(tag)); + secp256k1_sha256_initialize_tagged(hash_ctx, &sha, (unsigned char *) tag, sizeof(tag)); secp256k1_schnorrsig_sha256_tagged(&sha_optimized); test_sha256_eq(&sha, &sha_optimized); } @@ -849,6 +852,29 @@ static void test_schnorrsig_sign_internal(void) { CHECK(secp256k1_memcmp_var(sig, sig2, sizeof(sig)) == 0); } +DEFINE_SHA256_TRANSFORM_PROBE(sha256_schnorrsig) +static void test_schnorrsig_ctx_sha256(void) { + /* Check ctx-provided SHA256 compression override takes effect */ + secp256k1_context *ctx = secp256k1_context_clone(CTX); + unsigned char out_default[64], out_custom[64]; + unsigned char sk[32] = {1}, msg32[32] = {1}; + secp256k1_keypair keypair; + CHECK(secp256k1_keypair_create(ctx, &keypair, sk)); + + /* Default behavior. No ctx-provided SHA256 compression */ + CHECK(secp256k1_schnorrsig_sign32(ctx, out_default, msg32, &keypair, NULL)); + CHECK(!sha256_schnorrsig_called); + + /* Override SHA256 compression directly, bypassing the ctx setter sanity checks */ + ctx->hash_ctx.fn_sha256_compression = sha256_schnorrsig; + CHECK(secp256k1_schnorrsig_sign32(ctx, out_custom, msg32, &keypair, NULL)); + CHECK(sha256_schnorrsig_called); + /* Outputs must differ if custom compression was used */ + CHECK(secp256k1_memcmp_var(out_default, out_custom, 64) != 0); + + secp256k1_context_destroy(ctx); +} + #define N_SIGS 3 /* Creates N_SIGS valid signatures and verifies them with verify and * verify_batch (TODO). Then flips some bits and checks that verification now @@ -978,6 +1004,7 @@ static const struct tf_test_entry tests_schnorrsig[] = { CASE1(test_schnorrsig_sign), CASE1(test_schnorrsig_sign_verify), CASE1(test_schnorrsig_taproot), + CASE1(test_schnorrsig_ctx_sha256), }; #endif diff --git a/src/secp256k1.c b/src/secp256k1.c index 218ceafb31..e4b80fff24 100644 --- a/src/secp256k1.c +++ b/src/secp256k1.c @@ -60,6 +60,7 @@ * context_eq function. */ struct secp256k1_context_struct { secp256k1_ecmult_gen_context ecmult_gen_ctx; + secp256k1_hash_ctx hash_ctx; secp256k1_callback illegal_callback; secp256k1_callback error_callback; int declassify; @@ -67,6 +68,7 @@ struct secp256k1_context_struct { static const secp256k1_context secp256k1_context_static_ = { { 0 }, + { secp256k1_sha256_transform }, { secp256k1_default_illegal_callback_fn, 0 }, { secp256k1_default_error_callback_fn, 0 }, 0 @@ -129,10 +131,11 @@ secp256k1_context* secp256k1_context_preallocated_create(void* prealloc, unsigne ret = (secp256k1_context*)prealloc; ret->illegal_callback = default_illegal_callback; ret->error_callback = default_error_callback; + secp256k1_hash_ctx_init(&ret->hash_ctx); /* Flags have been checked by secp256k1_context_preallocated_size. */ VERIFY_CHECK((flags & SECP256K1_FLAGS_TYPE_MASK) == SECP256K1_FLAGS_TYPE_CONTEXT); - secp256k1_ecmult_gen_context_build(&ret->ecmult_gen_ctx); + secp256k1_ecmult_gen_context_build(&ret->ecmult_gen_ctx, &ret->hash_ctx); ret->declassify = !!(flags & SECP256K1_FLAGS_BIT_CONTEXT_DECLASSIFY); return ret; @@ -220,6 +223,22 @@ void secp256k1_context_set_error_callback(secp256k1_context* ctx, void (*fun)(co ctx->error_callback.data = data; } +void secp256k1_context_set_sha256_compression(secp256k1_context *ctx, secp256k1_sha256_compression_function fn_compression) { + VERIFY_CHECK(ctx != NULL); + ARG_CHECK_VOID(secp256k1_context_is_proper(ctx)); + if (!fn_compression) { /* Reset hash context */ + secp256k1_hash_ctx_init(&ctx->hash_ctx); + return; + } + /* Check and set */ + ARG_CHECK_VOID(secp256k1_selftest_sha256(fn_compression)); + ctx->hash_ctx.fn_sha256_compression = fn_compression; +} + +static SECP256K1_INLINE const secp256k1_hash_ctx* secp256k1_get_hash_context(const secp256k1_context *ctx) { + return &ctx->hash_ctx; +} + static secp256k1_scratch_space* secp256k1_scratch_space_create(const secp256k1_context* ctx, size_t max_size) { VERIFY_CHECK(ctx != NULL); return secp256k1_scratch_create(&ctx->error_callback, max_size); @@ -476,7 +495,7 @@ static SECP256K1_INLINE void buffer_append(unsigned char *buf, unsigned int *off *offset += len; } -static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) { +static int nonce_function_rfc6979_impl(const secp256k1_hash_ctx *hash_ctx, unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) { unsigned char keydata[112]; unsigned int offset = 0; secp256k1_rfc6979_hmac_sha256 rng; @@ -501,9 +520,9 @@ static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *m if (algo16 != NULL) { buffer_append(keydata, &offset, algo16, 16); } - secp256k1_rfc6979_hmac_sha256_initialize(&rng, keydata, offset); + secp256k1_rfc6979_hmac_sha256_initialize(hash_ctx, &rng, keydata, offset); for (i = 0; i <= counter; i++) { - secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32); + secp256k1_rfc6979_hmac_sha256_generate(hash_ctx, &rng, nonce32, 32); } secp256k1_rfc6979_hmac_sha256_finalize(&rng); @@ -512,6 +531,10 @@ static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *m return 1; } +static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) { + return nonce_function_rfc6979_impl(secp256k1_get_hash_context(secp256k1_context_static), nonce32, msg32, key32, algo16, data, counter); +} + const secp256k1_nonce_function secp256k1_nonce_function_rfc6979 = nonce_function_rfc6979; const secp256k1_nonce_function secp256k1_nonce_function_default = nonce_function_rfc6979; @@ -527,9 +550,6 @@ static int secp256k1_ecdsa_sign_inner(const secp256k1_context* ctx, secp256k1_sc if (recid) { *recid = 0; } - if (noncefp == NULL) { - noncefp = secp256k1_nonce_function_default; - } /* Fail if the secret key is invalid. */ is_sec_valid = secp256k1_scalar_set_b32_seckey(&sec, seckey); @@ -537,7 +557,14 @@ static int secp256k1_ecdsa_sign_inner(const secp256k1_context* ctx, secp256k1_sc secp256k1_scalar_set_b32(&msg, msg32, NULL); while (1) { int is_nonce_valid; - ret = !!noncefp(nonce32, msg32, seckey, NULL, (void*)noncedata, count); + + if (noncefp == NULL) { + /* Use ctx-aware function by default */ + ret = nonce_function_rfc6979_impl(secp256k1_get_hash_context(ctx), nonce32, msg32, seckey, NULL, (void*)noncedata, count); + } else { + ret = !!noncefp(nonce32, msg32, seckey, NULL, (void*)noncedata, count); + } + if (!ret) { break; } @@ -757,7 +784,7 @@ int secp256k1_context_randomize(secp256k1_context* ctx, const unsigned char *see ARG_CHECK(secp256k1_context_is_proper(ctx)); if (secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)) { - secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, seed32); + secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, secp256k1_get_hash_context(ctx), seed32); } return 1; } @@ -795,9 +822,9 @@ int secp256k1_tagged_sha256(const secp256k1_context* ctx, unsigned char *hash32, ARG_CHECK(tag != NULL); ARG_CHECK(msg != NULL); - secp256k1_sha256_initialize_tagged(&sha, tag, taglen); - secp256k1_sha256_write(&sha, msg, msglen); - secp256k1_sha256_finalize(&sha, hash32); + secp256k1_sha256_initialize_tagged(secp256k1_get_hash_context(ctx), &sha, tag, taglen); + secp256k1_sha256_write(secp256k1_get_hash_context(ctx), &sha, msg, msglen); + secp256k1_sha256_finalize(secp256k1_get_hash_context(ctx), &sha, hash32); secp256k1_sha256_clear(&sha); return 1; } diff --git a/src/selftest.h b/src/selftest.h index d083ac9524..de0e0597f5 100644 --- a/src/selftest.h +++ b/src/selftest.h @@ -11,7 +11,8 @@ #include -static int secp256k1_selftest_sha256(void) { +static int secp256k1_selftest_sha256(secp256k1_sha256_compression_function fn_compression) { + secp256k1_hash_ctx hash_ctx; static const char *input63 = "For this sample, this 63-byte string will be used as input data"; static const unsigned char output32[32] = { 0xf0, 0x8a, 0x78, 0xcb, 0xba, 0xee, 0x08, 0x2b, 0x05, 0x2a, 0xe0, 0x70, 0x8f, 0x32, 0xfa, 0x1e, @@ -20,13 +21,15 @@ static int secp256k1_selftest_sha256(void) { unsigned char out[32]; secp256k1_sha256 hasher; secp256k1_sha256_initialize(&hasher); - secp256k1_sha256_write(&hasher, (const unsigned char*)input63, 63); - secp256k1_sha256_finalize(&hasher, out); + hash_ctx.fn_sha256_compression = fn_compression; + secp256k1_sha256_write(&hash_ctx, &hasher, (const unsigned char*)input63, 63); + secp256k1_sha256_finalize(&hash_ctx, &hasher, out); return secp256k1_memcmp_var(out, output32, 32) == 0; } static int secp256k1_selftest_passes(void) { - return secp256k1_selftest_sha256(); + /* Use default sha256 compression */ + return secp256k1_selftest_sha256(secp256k1_sha256_transform); } #endif /* SECP256K1_SELFTEST_H */ diff --git a/src/testrand_impl.h b/src/testrand_impl.h index b84f5730a9..e1e5d858c1 100644 --- a/src/testrand_impl.h +++ b/src/testrand_impl.h @@ -22,12 +22,13 @@ SECP256K1_INLINE static void testrand_seed(const unsigned char *seed16) { unsigned char out32[32]; secp256k1_sha256 hash; int i; + const secp256k1_hash_ctx *hash_ctx = secp256k1_get_hash_context(secp256k1_context_static); /* Use SHA256(PREFIX || seed16) as initial state. */ secp256k1_sha256_initialize(&hash); - secp256k1_sha256_write(&hash, PREFIX, sizeof(PREFIX)); - secp256k1_sha256_write(&hash, seed16, 16); - secp256k1_sha256_finalize(&hash, out32); + secp256k1_sha256_write(hash_ctx, &hash, PREFIX, sizeof(PREFIX)); + secp256k1_sha256_write(hash_ctx, &hash, seed16, 16); + secp256k1_sha256_finalize(hash_ctx, &hash, out32); for (i = 0; i < 4; ++i) { uint64_t s = 0; int j; diff --git a/src/tests.c b/src/tests.c index fa580cc97e..7c3a96bcdd 100644 --- a/src/tests.c +++ b/src/tests.c @@ -132,6 +132,7 @@ static int ecmult_gen_context_eq(const secp256k1_ecmult_gen_context *a, const se static int context_eq(const secp256k1_context *a, const secp256k1_context *b) { return a->declassify == b->declassify && ecmult_gen_context_eq(&a->ecmult_gen_ctx, &b->ecmult_gen_ctx) + && a->hash_ctx.fn_sha256_compression == b->hash_ctx.fn_sha256_compression && a->illegal_callback.fn == b->illegal_callback.fn && a->illegal_callback.data == b->illegal_callback.data && a->error_callback.fn == b->error_callback.fn @@ -432,6 +433,146 @@ static void run_scratch_tests(void) { secp256k1_scratch_space_destroy(CTX, NULL); /* no-op */ } +/* A compression function that does nothing */ +static void invalid_sha256_compression(uint32_t *s, const unsigned char *msg, size_t rounds) { + (void)s; (void)msg; (void)rounds; +} + +static int own_transform_called = 0; +static void good_sha256_compression(uint32_t *s, const unsigned char *msg, size_t rounds) { + own_transform_called = 1; + secp256k1_sha256_transform(s, msg, rounds); +} + +static void run_plug_sha256_compression_tests(void) { + secp256k1_context *ctx, *ctx_cloned; + secp256k1_sha256 sha; + unsigned char sha_out[32]; + /* 1) Verify the context is initialized with the default compression function */ + ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); + CHECK(ctx->hash_ctx.fn_sha256_compression == secp256k1_sha256_transform); + + /* 2) Verify providing a bad compression function fails during set */ + CHECK_ILLEGAL_VOID(ctx, secp256k1_context_set_sha256_compression(ctx, invalid_sha256_compression)); + CHECK(ctx->hash_ctx.fn_sha256_compression == secp256k1_sha256_transform); + + /* 3) Provide sha256 to ctx and verify it is called when provided */ + own_transform_called = 0; + secp256k1_context_set_sha256_compression(ctx, good_sha256_compression); + CHECK(own_transform_called); + + /* 4) Verify callback makes it across clone */ + ctx_cloned = secp256k1_context_clone(ctx); + CHECK(ctx_cloned->hash_ctx.fn_sha256_compression == good_sha256_compression); + + /* 5) A hash operation should invoke the installed callback */ + own_transform_called = 0; + secp256k1_sha256_initialize(&sha); + secp256k1_sha256_write(secp256k1_get_hash_context(ctx), &sha, (const unsigned char*)"a", 1); + secp256k1_sha256_finalize(secp256k1_get_hash_context(ctx), &sha, sha_out); + CHECK(own_transform_called); + + /* 6) Unset sha256 and verify the default one is set again */ + secp256k1_context_set_sha256_compression(ctx, NULL); + CHECK(ctx->hash_ctx.fn_sha256_compression == secp256k1_sha256_transform); + + secp256k1_context_destroy(ctx); + secp256k1_context_destroy(ctx_cloned); +} + +static void run_sha256_multi_block_compression_tests(void) { + secp256k1_hash_ctx hash_ctx; + secp256k1_sha256 sha256_one; + secp256k1_sha256 sha256_two; + unsigned char out_one[32], out_two[32]; + + hash_ctx.fn_sha256_compression = secp256k1_sha256_transform; + + { /* 1) Writing one 64-byte full block vs two 32-byte blocks */ + const unsigned char data[64] = "totally serious test message to hash, definitely no random data"; + unsigned char data32[32]; + + secp256k1_sha256_initialize(&sha256_one); + secp256k1_sha256_initialize(&sha256_two); + + /* Write the 64-byte block */ + secp256k1_sha256_write(&hash_ctx, &sha256_one, data, 64); + secp256k1_sha256_finalize(&hash_ctx, &sha256_one, out_one); + + /* Write the two 32-byte blocks */ + memcpy(data32, data, 32); + secp256k1_sha256_write(&hash_ctx, &sha256_two, data32, 32); + memcpy(data32, data + 32, 32); + secp256k1_sha256_write(&hash_ctx, &sha256_two, data32, 32); + secp256k1_sha256_finalize(&hash_ctx, &sha256_two, out_two); + + CHECK(secp256k1_memcmp_var(out_one, out_two, 32) == 0); + } + + { /* 2) Writing one 80-byte block vs two 40-byte blocks */ + const unsigned char data[80] = "Genesis: The Times 03/Jan/2009 Chancellor on brink of second bailout for banks "; + unsigned char data40[40]; + + secp256k1_sha256_initialize(&sha256_one); + secp256k1_sha256_initialize(&sha256_two); + + /* Write the 80-byte block */ + secp256k1_sha256_write(&hash_ctx, &sha256_one, data, 80); + secp256k1_sha256_finalize(&hash_ctx, &sha256_one, out_one); + + /* Write the two 40-byte blocks */ + memcpy(data40, data, 40); + secp256k1_sha256_write(&hash_ctx, &sha256_two, data40, 40); + memcpy(data40, data + 40, 40); + secp256k1_sha256_write(&hash_ctx, &sha256_two, data40, 40); + secp256k1_sha256_finalize(&hash_ctx, &sha256_two, out_two); + + CHECK(secp256k1_memcmp_var(out_one, out_two, 32) == 0); + } + + { /* 3) Writing multiple consecutive full blocks in one write (128 bytes) */ + unsigned char data[128]; + unsigned char i; + for (i = 0; i < 128; i++) data[i] = i; + + secp256k1_sha256_initialize(&sha256_one); + secp256k1_sha256_initialize(&sha256_two); + + /* Single write of 128 bytes (two full 64-byte blocks) */ + secp256k1_sha256_write(&hash_ctx, &sha256_one, data, 128); + secp256k1_sha256_finalize(&hash_ctx, &sha256_one, out_one); + + /* Two separate writes of 64 bytes each */ + secp256k1_sha256_write(&hash_ctx, &sha256_two, data, 64); + secp256k1_sha256_write(&hash_ctx, &sha256_two, data + 64, 64); + secp256k1_sha256_finalize(&hash_ctx, &sha256_two, out_two); + + CHECK(secp256k1_memcmp_var(out_one, out_two, 32) == 0); + } + + { /* 4) Mixed small + large writes in sequence */ + unsigned char data[150]; + unsigned char i; + for (i = 0; i < 150; i++) data[i] = i; + + secp256k1_sha256_initialize(&sha256_one); + secp256k1_sha256_initialize(&sha256_two); + + /* Single write of 150 bytes */ + secp256k1_sha256_write(&hash_ctx, &sha256_one, data, 150); + secp256k1_sha256_finalize(&hash_ctx, &sha256_one, out_one); + + /* Split writes: 10, 64, 64, 12 bytes */ + secp256k1_sha256_write(&hash_ctx, &sha256_two, data, 10); + secp256k1_sha256_write(&hash_ctx, &sha256_two, data + 10, 64); + secp256k1_sha256_write(&hash_ctx, &sha256_two, data + 74, 64); + secp256k1_sha256_write(&hash_ctx, &sha256_two, data + 138, 12); + secp256k1_sha256_finalize(&hash_ctx, &sha256_two, out_two); + + CHECK(secp256k1_memcmp_var(out_one, out_two, 32) == 0); + } +} + static void run_ctz_tests(void) { static const uint32_t b32[] = {1, 0xffffffff, 0x5e56968f, 0xe0d63129}; static const uint64_t b64[] = {1, 0xffffffffffffffff, 0xbcd02462139b3fc3, 0x98b5f80c769693ef}; @@ -454,6 +595,7 @@ static void run_ctz_tests(void) { /***** HASH TESTS *****/ static void run_sha256_known_output_tests(void) { + const secp256k1_hash_ctx *hash_ctx = secp256k1_get_hash_context(CTX); static const char *inputs[] = { "", "abc", "message digest", "secure hash algorithm", "SHA256 is considered to be safe", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", @@ -489,10 +631,10 @@ static void run_sha256_known_output_tests(void) { j = repeat[i]; secp256k1_sha256_initialize(&hasher); while (j > 0) { - secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i]), strlen(inputs[i])); + secp256k1_sha256_write(hash_ctx, &hasher, (const unsigned char*)(inputs[i]), strlen(inputs[i])); j--; } - secp256k1_sha256_finalize(&hasher, out); + secp256k1_sha256_finalize(hash_ctx, &hasher, out); CHECK(secp256k1_memcmp_var(out, outputs[i], 32) == 0); /* 2. Run: split the input bytestrings randomly before writing */ if (strlen(inputs[i]) > 0) { @@ -500,11 +642,11 @@ static void run_sha256_known_output_tests(void) { secp256k1_sha256_initialize(&hasher); j = repeat[i]; while (j > 0) { - secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i]), split); - secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i] + split), strlen(inputs[i]) - split); + secp256k1_sha256_write(hash_ctx, &hasher, (const unsigned char*)(inputs[i]), split); + secp256k1_sha256_write(hash_ctx, &hasher, (const unsigned char*)(inputs[i] + split), strlen(inputs[i]) - split); j--; } - secp256k1_sha256_finalize(&hasher, out); + secp256k1_sha256_finalize(hash_ctx, &hasher, out); CHECK(secp256k1_memcmp_var(out, outputs[i], 32) == 0); } } @@ -602,12 +744,13 @@ static void run_sha256_counter_tests(void) { {0x2c, 0xf3, 0xa9, 0xf6, 0x15, 0x25, 0x80, 0x70, 0x76, 0x99, 0x7d, 0xf1, 0xc3, 0x2f, 0xa3, 0x31, 0xff, 0x92, 0x35, 0x2e, 0x8d, 0x04, 0x13, 0x33, 0xd8, 0x0d, 0xdb, 0x4a, 0xf6, 0x8c, 0x03, 0x34}, {0xec, 0x12, 0x24, 0x9f, 0x35, 0xa4, 0x29, 0x8b, 0x9e, 0x4a, 0x95, 0xf8, 0x61, 0xaf, 0x61, 0xc5, 0x66, 0x55, 0x3e, 0x3f, 0x2a, 0x98, 0xea, 0x71, 0x16, 0x6b, 0x1c, 0xd9, 0xe4, 0x09, 0xd2, 0x8e}, }; + const secp256k1_hash_ctx *hash_ctx = secp256k1_get_hash_context(CTX); unsigned int i; for (i = 0; i < sizeof(midstates)/sizeof(midstates[0]); i++) { unsigned char out[32]; secp256k1_sha256 hasher = midstates[i]; - secp256k1_sha256_write(&hasher, (const unsigned char*)input, strlen(input)); - secp256k1_sha256_finalize(&hasher, out); + secp256k1_sha256_write(hash_ctx, &hasher, (const unsigned char*)input, strlen(input)); + secp256k1_sha256_finalize(hash_ctx, &hasher, out); CHECK(secp256k1_memcmp_var(out, outputs[i], 32) == 0); } } @@ -624,9 +767,9 @@ static void test_sha256_eq(const secp256k1_sha256 *sha1, const secp256k1_sha256 } /* Convenience function for using test_sha256_eq to verify the correctness of a * tagged hash midstate. This function is used by some module tests. */ -static void test_sha256_tag_midstate(secp256k1_sha256 *sha_tagged, const unsigned char *tag, size_t taglen) { +static void test_sha256_tag_midstate(const secp256k1_hash_ctx *hash_ctx, secp256k1_sha256 *sha_tagged, const unsigned char *tag, size_t taglen) { secp256k1_sha256 sha; - secp256k1_sha256_initialize_tagged(&sha, tag, taglen); + secp256k1_sha256_initialize_tagged(hash_ctx, &sha, tag, taglen); test_sha256_eq(&sha, sha_tagged); } @@ -656,19 +799,20 @@ static void run_hmac_sha256_tests(void) { {0x9b, 0x09, 0xff, 0xa7, 0x1b, 0x94, 0x2f, 0xcb, 0x27, 0x63, 0x5f, 0xbc, 0xd5, 0xb0, 0xe9, 0x44, 0xbf, 0xdc, 0x63, 0x64, 0x4f, 0x07, 0x13, 0x93, 0x8a, 0x7f, 0x51, 0x53, 0x5c, 0x3a, 0x35, 0xe2} }; int i; + const secp256k1_hash_ctx *hash_ctx = secp256k1_get_hash_context(CTX); for (i = 0; i < 6; i++) { secp256k1_hmac_sha256 hasher; unsigned char out[32]; - secp256k1_hmac_sha256_initialize(&hasher, (const unsigned char*)(keys[i]), strlen(keys[i])); - secp256k1_hmac_sha256_write(&hasher, (const unsigned char*)(inputs[i]), strlen(inputs[i])); - secp256k1_hmac_sha256_finalize(&hasher, out); + secp256k1_hmac_sha256_initialize(hash_ctx, &hasher, (const unsigned char*)(keys[i]), strlen(keys[i])); + secp256k1_hmac_sha256_write(hash_ctx, &hasher, (const unsigned char*)(inputs[i]), strlen(inputs[i])); + secp256k1_hmac_sha256_finalize(hash_ctx, &hasher, out); CHECK(secp256k1_memcmp_var(out, outputs[i], 32) == 0); if (strlen(inputs[i]) > 0) { int split = testrand_int(strlen(inputs[i])); - secp256k1_hmac_sha256_initialize(&hasher, (const unsigned char*)(keys[i]), strlen(keys[i])); - secp256k1_hmac_sha256_write(&hasher, (const unsigned char*)(inputs[i]), split); - secp256k1_hmac_sha256_write(&hasher, (const unsigned char*)(inputs[i] + split), strlen(inputs[i]) - split); - secp256k1_hmac_sha256_finalize(&hasher, out); + secp256k1_hmac_sha256_initialize(hash_ctx, &hasher, (const unsigned char*)(keys[i]), strlen(keys[i])); + secp256k1_hmac_sha256_write(hash_ctx, &hasher, (const unsigned char*)(inputs[i]), split); + secp256k1_hmac_sha256_write(hash_ctx, &hasher, (const unsigned char*)(inputs[i] + split), strlen(inputs[i]) - split); + secp256k1_hmac_sha256_finalize(hash_ctx, &hasher, out); CHECK(secp256k1_memcmp_var(out, outputs[i], 32) == 0); } } @@ -689,27 +833,28 @@ static void run_rfc6979_hmac_sha256_tests(void) { {0x75, 0x97, 0x88, 0x7c, 0xbd, 0x76, 0x32, 0x1f, 0x32, 0xe3, 0x04, 0x40, 0x67, 0x9a, 0x22, 0xcf, 0x7f, 0x8d, 0x9d, 0x2e, 0xac, 0x39, 0x0e, 0x58, 0x1f, 0xea, 0x09, 0x1c, 0xe2, 0x02, 0xba, 0x94} }; + const secp256k1_hash_ctx *hash_ctx = secp256k1_get_hash_context(CTX); secp256k1_rfc6979_hmac_sha256 rng; unsigned char out[32]; int i; - secp256k1_rfc6979_hmac_sha256_initialize(&rng, key1, 64); + secp256k1_rfc6979_hmac_sha256_initialize(hash_ctx, &rng, key1, 64); for (i = 0; i < 3; i++) { - secp256k1_rfc6979_hmac_sha256_generate(&rng, out, 32); + secp256k1_rfc6979_hmac_sha256_generate(hash_ctx, &rng, out, 32); CHECK(secp256k1_memcmp_var(out, out1[i], 32) == 0); } secp256k1_rfc6979_hmac_sha256_finalize(&rng); - secp256k1_rfc6979_hmac_sha256_initialize(&rng, key1, 65); + secp256k1_rfc6979_hmac_sha256_initialize(hash_ctx, &rng, key1, 65); for (i = 0; i < 3; i++) { - secp256k1_rfc6979_hmac_sha256_generate(&rng, out, 32); + secp256k1_rfc6979_hmac_sha256_generate(hash_ctx, &rng, out, 32); CHECK(secp256k1_memcmp_var(out, out1[i], 32) != 0); } secp256k1_rfc6979_hmac_sha256_finalize(&rng); - secp256k1_rfc6979_hmac_sha256_initialize(&rng, key2, 64); + secp256k1_rfc6979_hmac_sha256_initialize(hash_ctx, &rng, key2, 64); for (i = 0; i < 3; i++) { - secp256k1_rfc6979_hmac_sha256_generate(&rng, out, 32); + secp256k1_rfc6979_hmac_sha256_generate(hash_ctx, &rng, out, 32); CHECK(secp256k1_memcmp_var(out, out2[i], 32) == 0); } secp256k1_rfc6979_hmac_sha256_finalize(&rng); @@ -746,10 +891,11 @@ static void run_sha256_initialize_midstate_tests(void) { 0xa9ec59eaul, 0x9b4c2ffful, 0x400821e2ul, 0x0dcf3847ul, 0xbe7ea179ul, 0xa5772bdcul, 0x7d29bfe3ul, 0xa486b855ul }; + const secp256k1_hash_ctx *hash_ctx = secp256k1_get_hash_context(CTX); secp256k1_sha256 sha; secp256k1_sha256_initialize_midstate(&sha, 64, midstate); - test_sha256_tag_midstate(&sha, tag, sizeof(tag) - 1); + test_sha256_tag_midstate(hash_ctx, &sha, tag, sizeof(tag) - 1); } /***** MODINV TESTS *****/ @@ -5501,11 +5647,11 @@ static void test_ecmult_accumulate(secp256k1_sha256* acc, const secp256k1_scalar if (secp256k1_ge_is_infinity(&r)) { /* Store infinity as 0x00 */ const unsigned char zerobyte[1] = {0}; - secp256k1_sha256_write(acc, zerobyte, 1); + secp256k1_sha256_write(secp256k1_get_hash_context(CTX), acc, zerobyte, 1); } else { /* Store other points using their uncompressed serialization. */ secp256k1_eckey_pubkey_serialize65(&r, bytes); - secp256k1_sha256_write(acc, bytes, sizeof(bytes)); + secp256k1_sha256_write(secp256k1_get_hash_context(CTX), acc, bytes, sizeof(bytes)); } } @@ -5547,7 +5693,7 @@ static void test_ecmult_constants_2bit(void) { test_ecmult_accumulate(&acc, &x, scratch); } } - secp256k1_sha256_finalize(&acc, b32); + secp256k1_sha256_finalize(secp256k1_get_hash_context(CTX), &acc, b32); CHECK(secp256k1_memcmp_var(b32, expected32, 32) == 0); secp256k1_scratch_space_destroy(CTX, scratch); @@ -5566,6 +5712,7 @@ static void test_ecmult_constants_sha(uint32_t prefix, size_t iter, const unsign unsigned char b32[32]; unsigned char inp[6]; size_t i; + const secp256k1_hash_ctx *hash_ctx = secp256k1_get_hash_context(CTX); secp256k1_scratch_space *scratch = secp256k1_scratch_space_create(CTX, 65536); inp[0] = prefix & 0xFF; @@ -5585,12 +5732,12 @@ static void test_ecmult_constants_sha(uint32_t prefix, size_t iter, const unsign inp[4] = i & 0xff; inp[5] = (i >> 8) & 0xff; secp256k1_sha256_initialize(&gen); - secp256k1_sha256_write(&gen, inp, sizeof(inp)); - secp256k1_sha256_finalize(&gen, b32); + secp256k1_sha256_write(hash_ctx, &gen, inp, sizeof(inp)); + secp256k1_sha256_finalize(hash_ctx, &gen, b32); secp256k1_scalar_set_b32(&x, b32, NULL); test_ecmult_accumulate(&acc, &x, scratch); } - secp256k1_sha256_finalize(&acc, b32); + secp256k1_sha256_finalize(hash_ctx, &acc, b32); CHECK(secp256k1_memcmp_var(b32, expected32, 32) == 0); secp256k1_scratch_space_destroy(CTX, scratch); @@ -5644,7 +5791,7 @@ static void test_ecmult_gen_blind(void) { testrand256(seed32); b = CTX->ecmult_gen_ctx.scalar_offset; p = CTX->ecmult_gen_ctx.ge_offset; - secp256k1_ecmult_gen_blind(&CTX->ecmult_gen_ctx, seed32); + secp256k1_ecmult_gen_blind(&CTX->ecmult_gen_ctx, secp256k1_get_hash_context(CTX), seed32); CHECK(!secp256k1_scalar_eq(&b, &CTX->ecmult_gen_ctx.scalar_offset)); secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &pgej2, &key); CHECK(!gej_xyz_equals_gej(&pgej, &pgej2)); @@ -5657,10 +5804,10 @@ static void test_ecmult_gen_blind_reset(void) { /* Test ecmult_gen() blinding reset and confirm that the blinding is consistent. */ secp256k1_scalar b; secp256k1_ge p1, p2; - secp256k1_ecmult_gen_blind(&CTX->ecmult_gen_ctx, 0); + secp256k1_ecmult_gen_blind(&CTX->ecmult_gen_ctx, secp256k1_get_hash_context(CTX), 0); b = CTX->ecmult_gen_ctx.scalar_offset; p1 = CTX->ecmult_gen_ctx.ge_offset; - secp256k1_ecmult_gen_blind(&CTX->ecmult_gen_ctx, 0); + secp256k1_ecmult_gen_blind(&CTX->ecmult_gen_ctx, secp256k1_get_hash_context(CTX), 0); CHECK(secp256k1_scalar_eq(&b, &CTX->ecmult_gen_ctx.scalar_offset)); p2 = CTX->ecmult_gen_ctx.ge_offset; CHECK(secp256k1_ge_eq_var(&p1, &p2)); @@ -7122,7 +7269,7 @@ static void run_ecdsa_der_parse(void) { } /* Tests several edge cases. */ -static void test_ecdsa_edge_cases(void) { +static void run_ecdsa_edge_cases(void) { int t; secp256k1_ecdsa_signature sig; @@ -7455,8 +7602,25 @@ static void test_ecdsa_edge_cases(void) { } } -static void run_ecdsa_edge_cases(void) { - test_ecdsa_edge_cases(); +DEFINE_SHA256_TRANSFORM_PROBE(sha256_ecdsa) +static void ecdsa_ctx_sha256(void) { + /* Check ctx-provided SHA256 compression override takes effect */ + secp256k1_context *ctx = secp256k1_context_clone(CTX); + secp256k1_ecdsa_signature out_default, out_custom; + unsigned char sk[32] = {1}, msg32[32] = {1}; + + /* Default behavior. No ctx-provided SHA256 compression */ + CHECK(secp256k1_ecdsa_sign(ctx, &out_default, msg32, sk, NULL, NULL)); + CHECK(!sha256_ecdsa_called); + + /* Override SHA256 compression directly, bypassing the ctx setter sanity checks */ + ctx->hash_ctx.fn_sha256_compression = sha256_ecdsa; + CHECK(secp256k1_ecdsa_sign(ctx, &out_custom, msg32, sk, NULL, NULL)); + CHECK(sha256_ecdsa_called); + /* Outputs must differ if custom compression was used */ + CHECK(secp256k1_memcmp_var(out_default.data, out_custom.data, 64) != 0); + + secp256k1_context_destroy(ctx); } /** Wycheproof tests @@ -7467,6 +7631,7 @@ static void test_ecdsa_wycheproof(void) { #include "wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.h" int t; + const secp256k1_hash_ctx *hash_ctx = secp256k1_get_hash_context(CTX); for (t = 0; t < SECP256K1_ECDSA_WYCHEPROOF_NUMBER_TESTVECTORS; t++) { secp256k1_ecdsa_signature signature; secp256k1_sha256 hasher; @@ -7481,8 +7646,8 @@ static void test_ecdsa_wycheproof(void) { secp256k1_sha256_initialize(&hasher); msg = &wycheproof_ecdsa_messages[testvectors[t].msg_offset]; - secp256k1_sha256_write(&hasher, msg, testvectors[t].msg_len); - secp256k1_sha256_finalize(&hasher, out); + secp256k1_sha256_write(hash_ctx, &hasher, msg, testvectors[t].msg_len); + secp256k1_sha256_finalize(hash_ctx, &hasher, out); sig = &wycheproof_ecdsa_signatures[testvectors[t].sig_offset]; if (secp256k1_ecdsa_signature_parse_der(CTX, &signature, sig, testvectors[t].sig_len) == 1) { @@ -7746,6 +7911,8 @@ static const struct tf_test_entry tests_general[] = { CASE(all_static_context_tests), CASE(deprecated_context_flags_test), CASE(scratch_tests), + CASE(plug_sha256_compression_tests), + CASE(sha256_multi_block_compression_tests), }; static const struct tf_test_entry tests_integer[] = { @@ -7816,6 +7983,7 @@ static const struct tf_test_entry tests_ecdsa[] = { CASE(ecdsa_end_to_end), CASE(ecdsa_edge_cases), CASE(ecdsa_wycheproof), + CASE1(ecdsa_ctx_sha256), }; static const struct tf_test_entry tests_utils[] = { diff --git a/src/testutil.h b/src/testutil.h index 93ee3d58b5..8fa69a02c9 100644 --- a/src/testutil.h +++ b/src/testutil.h @@ -11,6 +11,15 @@ #include "testrand.h" #include "util.h" +/* Helper for when we need to check that the ctx-provided sha256 compression was called */ +#define DEFINE_SHA256_TRANSFORM_PROBE(name) \ + static int name##_called = 0; \ + static void name(uint32_t *s, const unsigned char *msg, size_t rounds) { \ + name##_called = 1; \ + secp256k1_sha256_transform(s, msg, rounds); \ + s[0] ^= 0xdeadbeef; /* intentional perturbation for testing */ \ + } + /* group order of the secp256k1 curve in 32-byte big endian representation */ static const unsigned char secp256k1_group_order_bytes[32] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,