diff --git a/src/secp256k1/.github/actions/install-homebrew-valgrind/action.yml b/src/secp256k1/.github/actions/install-homebrew-valgrind/action.yml index e9aa615083..c4e0b5d910 100644 --- a/src/secp256k1/.github/actions/install-homebrew-valgrind/action.yml +++ b/src/secp256k1/.github/actions/install-homebrew-valgrind/action.yml @@ -5,6 +5,7 @@ runs: steps: - run: | brew tap LouisBrunner/valgrind + brew trust --formula LouisBrunner/valgrind/valgrind brew fetch --HEAD LouisBrunner/valgrind/valgrind echo "CI_HOMEBREW_CELLAR_VALGRIND=$(brew --cellar valgrind)" >> "$GITHUB_ENV" shell: bash diff --git a/src/secp256k1/CMakeLists.txt b/src/secp256k1/CMakeLists.txt index c55cf10fa7..c894f41af7 100644 --- a/src/secp256k1/CMakeLists.txt +++ b/src/secp256k1/CMakeLists.txt @@ -156,6 +156,8 @@ if(MSVC) string(REGEX REPLACE "/DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}") string(REGEX REPLACE "/DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}") string(REGEX REPLACE "/DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL}") + # Match GCC/Clang's size-optimization macro for the inline guard + add_compile_definitions($<$:__OPTIMIZE_SIZE__=1>) else() string(REGEX REPLACE "-DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}") string(REGEX REPLACE "-DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}") diff --git a/src/secp256k1/README.md b/src/secp256k1/README.md index af62b8323c..69456dc8ea 100644 --- a/src/secp256k1/README.md +++ b/src/secp256k1/README.md @@ -37,20 +37,21 @@ This can be done with the following steps: ``` 4. Check out the latest release tag, e.g. ``` - git checkout v0.6.0 + git checkout v0.7.1 ``` 5. Use git to verify the GPG signature: ``` - % git tag -v v0.6.0 | grep -C 3 'Good signature' + % git tag -v v0.7.1 | grep -C 3 'Good signature' - gpg: Signature made Mon 04 Nov 2024 12:14:44 PM EST - gpg: using RSA key 4BBB845A6F5A65A69DFAEC234861DBF262123605 - gpg: Good signature from "Jonas Nick " [unknown] - gpg: aka "Jonas Nick " [unknown] + gpg: Signature made Mon 26 Jan 2026 07:42:46 PM UTC + gpg: using RSA key 2840EAABF4BC9F0FFD716AFAFBAFCC46DE2D3FE2 + gpg: Good signature from "Pieter Wuille " [unknown] + gpg: aka "Pieter Wuille " [full] + gpg: aka "[jpeg image of size 5996]" [undefined] gpg: WARNING: This key is not certified with a trusted signature! gpg: There is no indication that the signature belongs to the owner. - Primary key fingerprint: 36C7 1A37 C9D9 88BD E825 08D9 B1A7 0E4F 8DCD 0366 - Subkey fingerprint: 4BBB 845A 6F5A 65A6 9DFA EC23 4861 DBF2 6212 3605 + Primary key fingerprint: 133E AC17 9436 F14A 5CF1 B794 860F EB80 4E66 9320 + Subkey fingerprint: 2840 EAAB F4BC 9F0F FD71 6AFA FBAF CC46 DE2D 3FE2 ``` Building with Autotools diff --git a/src/secp256k1/SECURITY.md b/src/secp256k1/SECURITY.md index b515cc1c8e..4be32e421d 100644 --- a/src/secp256k1/SECURITY.md +++ b/src/secp256k1/SECURITY.md @@ -9,7 +9,6 @@ The following keys may be used to communicate sensitive information to developer | Name | Fingerprint | |------|-------------| | Pieter Wuille | 133E AC17 9436 F14A 5CF1 B794 860F EB80 4E66 9320 | -| Jonas Nick | 36C7 1A37 C9D9 88BD E825 08D9 B1A7 0E4F 8DCD 0366 | | Tim Ruffing | 09E0 3F87 1092 E40E 106E 902B 33BC 86AB 80FF 5516 | You can import a key by running the following command with that individual’s fingerprint: `gpg --keyserver hkps://keys.openpgp.org --recv-keys ""` Ensure that you put quotes around fingerprints containing spaces. diff --git a/src/secp256k1/cmake/SetLibtoolAbiVersion.cmake b/src/secp256k1/cmake/SetLibtoolAbiVersion.cmake new file mode 100644 index 0000000000..0e981053df --- /dev/null +++ b/src/secp256k1/cmake/SetLibtoolAbiVersion.cmake @@ -0,0 +1,61 @@ +#[=[ +This emulates Libtool to make sure Libtool and CMake agree on +the ABI version and file naming for shared libraries. + +The `version_type` variable is set in `libtool.m4` (installed +by autoreconf into autotools-aux/m4/). +For the `major` and `versuffix` variables, see below "Calculate +the version variables" in `ltmain.sh` (installed by autoreconf +into autotools-aux/). +]=] +function(set_libtool_abi_version target current revision age) + if(CMAKE_SYSTEM_NAME MATCHES "^(Linux|FreeBSD)$") + # version_type = linux | freebsd-elf + # major = $current - $age + # versuffix = $major.$age.$revision + math(EXPR _major "${current} - ${age}") + set_target_properties(${target} PROPERTIES + SOVERSION ${_major} + VERSION ${_major}.${age}.${revision} + ) + elseif(CMAKE_SYSTEM_NAME STREQUAL "NetBSD") + # version_type = sunos + # major = $current + # versuffix = $current.$revision + set_target_properties(${target} PROPERTIES + SOVERSION ${current} + VERSION ${current}.${revision} + ) + elseif(CMAKE_SYSTEM_NAME STREQUAL "OpenBSD") + # version_type = sunos + # major = $current + # versuffix = $current.$revision + set_target_properties(${target} PROPERTIES + # OpenBSD has no `soname_spec` defined in `libtool.m4`. + VERSION ${current}.${revision} + ) + elseif(APPLE) + # version_type = darwin + # major = $current - $age + math(EXPR _major "${current} - ${age}") + math(EXPR _compatibility "${current} + 1") + set_target_properties(${target} PROPERTIES + SOVERSION ${_major} + MACHO_COMPATIBILITY_VERSION ${_compatibility} + MACHO_CURRENT_VERSION ${_compatibility}.${revision} + ) + elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows") + # version_type = windows + # major = $current - $age + # versuffix = $major + math(EXPR _major "${current} - ${age}") + set(_windows_name "secp256k1") + if(MSVC) + set(_windows_name "${PROJECT_NAME}") + endif() + set_target_properties(${target} PROPERTIES + ARCHIVE_OUTPUT_NAME "${_windows_name}" + RUNTIME_OUTPUT_NAME "${_windows_name}-${_major}" + ) + endif() +endfunction() diff --git a/src/secp256k1/include/secp256k1.h b/src/secp256k1/include/secp256k1.h index b7ec6a2283..2f3383e16a 100644 --- a/src/secp256k1/include/secp256k1.h +++ b/src/secp256k1/include/secp256k1.h @@ -687,7 +687,7 @@ SECP256K1_API const secp256k1_nonce_function secp256k1_nonce_function_default; * Returns: 1: signature created * 0: the nonce generation function failed, or the secret key was invalid. * Args: ctx: pointer to a context object (not secp256k1_context_static). - * Out: sig: pointer to an array where the signature will be placed. + * Out: sig: pointer to a signature object. * In: msghash32: the 32-byte message hash being signed. * seckey: pointer to a 32-byte secret key. * noncefp: pointer to a nonce generation function. If NULL, diff --git a/src/secp256k1/include/secp256k1_rangeproof.h b/src/secp256k1/include/secp256k1_rangeproof.h index 0224972f55..338c724397 100644 --- a/src/secp256k1/include/secp256k1_rangeproof.h +++ b/src/secp256k1/include/secp256k1_rangeproof.h @@ -125,7 +125,14 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_rangeproof_rewind( * commit: the commitment being proved. * blind: 32-byte blinding factor used by commit. The blinding factor may be all-zeros as long as min_bits is set to 3 or greater. * This is a side-effect of the underlying crypto, not a deliberate API choice, but it may be useful when balancing CT transactions. - * nonce: 32-byte secret nonce used to initialize the proof (value can be reverse-engineered out of the proof if this secret is known.) + * nonce: 32-byte secret nonce used to initialize the proof. + * + * Each call to this function must have a UNIQUE nonce that + * MUST NOT BE REUSED in subsequent calls. The nonce must be + * KEPT SECRET except from parties authorized to rewind the + * proof. Anyone who knows the nonce can recover `value` and + * `blind` from the proof. Reusing the nonce may expose `blind` + * even to parties that do not know the nonce. * exp: Base-10 exponent. Digits below above will be made public, but the proof will be made smaller. Allowed range is -1 to 18. * (-1 is a special case that makes the value public. 0 is the most private.) * min_bits: Number of bits of the value to keep private. (0 = auto/minimal, - 64). diff --git a/src/secp256k1/include/secp256k1_recovery.h b/src/secp256k1/include/secp256k1_recovery.h index 2430f99397..45f20aba76 100644 --- a/src/secp256k1/include/secp256k1_recovery.h +++ b/src/secp256k1/include/secp256k1_recovery.h @@ -73,7 +73,7 @@ SECP256K1_API int secp256k1_ecdsa_recoverable_signature_serialize_compact( * Returns: 1: signature created * 0: the nonce generation function failed, or the secret key was invalid. * Args: ctx: pointer to a context object (not secp256k1_context_static). - * Out: sig: pointer to an array where the signature will be placed. + * Out: sig: pointer to a signature object. * In: msghash32: the 32-byte message hash being signed. * seckey: pointer to a 32-byte secret key. * noncefp: pointer to a nonce generation function. If NULL, diff --git a/src/secp256k1/src/CMakeLists.txt b/src/secp256k1/src/CMakeLists.txt index ddd5d3148c..4431fd47d0 100644 --- a/src/secp256k1/src/CMakeLists.txt +++ b/src/secp256k1/src/CMakeLists.txt @@ -155,35 +155,12 @@ set_target_properties(secp256k1_objs PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "$" ) -# This emulates Libtool to make sure Libtool and CMake agree on the ABI version, -# see below "Calculate the version variables" in autotools-aux/ltmain.sh. -math(EXPR ${PROJECT_NAME}_soversion "${${PROJECT_NAME}_LIB_VERSION_CURRENT} - ${${PROJECT_NAME}_LIB_VERSION_AGE}") -set_target_properties(secp256k1 PROPERTIES - SOVERSION ${${PROJECT_NAME}_soversion} +include(SetLibtoolAbiVersion) +set_libtool_abi_version(secp256k1 + ${${PROJECT_NAME}_LIB_VERSION_CURRENT} + ${${PROJECT_NAME}_LIB_VERSION_REVISION} + ${${PROJECT_NAME}_LIB_VERSION_AGE} ) -if(CMAKE_SYSTEM_NAME MATCHES "^(Linux|FreeBSD)$") - set_target_properties(secp256k1 PROPERTIES - VERSION ${${PROJECT_NAME}_soversion}.${${PROJECT_NAME}_LIB_VERSION_AGE}.${${PROJECT_NAME}_LIB_VERSION_REVISION} - ) -elseif(APPLE) - math(EXPR ${PROJECT_NAME}_compatibility_version "${${PROJECT_NAME}_LIB_VERSION_CURRENT} + 1") - set_target_properties(secp256k1 PROPERTIES - MACHO_COMPATIBILITY_VERSION ${${PROJECT_NAME}_compatibility_version} - MACHO_CURRENT_VERSION ${${PROJECT_NAME}_compatibility_version}.${${PROJECT_NAME}_LIB_VERSION_REVISION} - ) - unset(${PROJECT_NAME}_compatibility_version) -elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows") - set(${PROJECT_NAME}_windows "secp256k1") - if(MSVC) - set(${PROJECT_NAME}_windows "${PROJECT_NAME}") - endif() - set_target_properties(secp256k1 PROPERTIES - ARCHIVE_OUTPUT_NAME "${${PROJECT_NAME}_windows}" - RUNTIME_OUTPUT_NAME "${${PROJECT_NAME}_windows}-${${PROJECT_NAME}_soversion}" - ) - unset(${PROJECT_NAME}_windows) -endif() -unset(${PROJECT_NAME}_soversion) if(SECP256K1_BUILD_BENCHMARK) add_executable(bench bench.c) diff --git a/src/secp256k1/src/bench_ecmult.c b/src/secp256k1/src/bench_ecmult.c index eb546db414..12d550a6ae 100644 --- a/src/secp256k1/src/bench_ecmult.c +++ b/src/secp256k1/src/bench_ecmult.c @@ -88,7 +88,7 @@ static void bench_ecmult_teardown_helper(bench_data* data, size_t* seckey_offset secp256k1_scalar_add(&sum_scalars, &sum_scalars, &s); } } - secp256k1_ecmult_gen(&data->ctx->ecmult_gen_ctx, &tmp, &sum_scalars); + secp256k1_ecmult_gen_gej(&data->ctx->ecmult_gen_ctx, &tmp, &sum_scalars); CHECK(secp256k1_gej_eq_var(&tmp, &sum_output)); } @@ -104,7 +104,7 @@ static void bench_ecmult_gen(void* arg, int iters) { int i; for (i = 0; i < iters; ++i) { - secp256k1_ecmult_gen(&data->ctx->ecmult_gen_ctx, &data->output[i], &data->scalars[(data->offset1+i) % POINTS]); + secp256k1_ecmult_gen_gej(&data->ctx->ecmult_gen_ctx, &data->output[i], &data->scalars[(data->offset1+i) % POINTS]); } } diff --git a/src/secp256k1/src/bench_internal.c b/src/secp256k1/src/bench_internal.c index bdfc338040..6f122d0f22 100644 --- a/src/secp256k1/src/bench_internal.c +++ b/src/secp256k1/src/bench_internal.c @@ -203,6 +203,17 @@ static void bench_field_normalize(void* arg, int iters) { } } +static void bench_field_normalize_var(void* arg, int iters) { + int i; + bench_inv *data = (bench_inv*)arg; + + /* Note that this benchmark measures the optimistic path. The worst-case path with the final + reduction is very unlikely to be needed, so this is representative of the common case. */ + for (i = 0; i < iters; i++) { + secp256k1_fe_normalize_var(&data->fe[0]); + } +} + static void bench_field_normalize_weak(void* arg, int iters) { int i; bench_inv *data = (bench_inv*)arg; @@ -449,6 +460,7 @@ int main(int argc, char **argv) { if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "half")) run_benchmark("field_half", bench_field_half, bench_setup, NULL, &data, 10, iters*100); if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "normalize")) run_benchmark("field_normalize", bench_field_normalize, bench_setup, NULL, &data, 10, iters*100); + if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "normalize")) run_benchmark("field_normalize_var", bench_field_normalize_var, bench_setup, NULL, &data, 10, iters*100); if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "normalize")) run_benchmark("field_normalize_weak", bench_field_normalize_weak, bench_setup, NULL, &data, 10, iters*100); if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "sqr")) run_benchmark("field_sqr", bench_field_sqr, bench_setup, NULL, &data, 10, iters*10); if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "mul")) run_benchmark("field_mul", bench_field_mul, bench_setup, NULL, &data, 10, iters*10); diff --git a/src/secp256k1/src/ctime_tests.c b/src/secp256k1/src/ctime_tests.c index 3a12d0bcd8..30cbe7a131 100644 --- a/src/secp256k1/src/ctime_tests.c +++ b/src/secp256k1/src/ctime_tests.c @@ -48,6 +48,11 @@ #include "../include/secp256k1_ecdsa_adaptor.h" #endif +#if defined(__GNUC__) +# pragma GCC diagnostic push +# pragma GCC diagnostic warning "-Wunused-function" +#endif + static void run_tests(secp256k1_context *ctx, unsigned char *key); int main(void) { @@ -357,3 +362,7 @@ static void run_tests(secp256k1_context *ctx, unsigned char *key) { } #endif } + +#if defined(__GNUC__) +# pragma GCC diagnostic pop +#endif diff --git a/src/secp256k1/src/ecdsa_impl.h b/src/secp256k1/src/ecdsa_impl.h index 163539ebc1..32f1e58500 100644 --- a/src/secp256k1/src/ecdsa_impl.h +++ b/src/secp256k1/src/ecdsa_impl.h @@ -273,14 +273,12 @@ static int secp256k1_ecdsa_sig_verify(const secp256k1_scalar *sigr, const secp25 static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context *ctx, secp256k1_scalar *sigr, secp256k1_scalar *sigs, const secp256k1_scalar *seckey, const secp256k1_scalar *message, const secp256k1_scalar *nonce, int *recid) { unsigned char b[32]; - secp256k1_gej rp; secp256k1_ge r; secp256k1_scalar n; int overflow = 0; int high; - secp256k1_ecmult_gen(ctx, &rp, nonce); - secp256k1_ge_set_gej(&r, &rp); + secp256k1_ecmult_gen_ge(ctx, &r, nonce); secp256k1_fe_normalize(&r.x); secp256k1_fe_normalize(&r.y); secp256k1_fe_get_b32(b, &r.x); @@ -296,7 +294,6 @@ static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context *ctx, sec secp256k1_scalar_inverse(sigs, nonce); secp256k1_scalar_mul(sigs, sigs, &n); secp256k1_scalar_clear(&n); - secp256k1_gej_clear(&rp); secp256k1_ge_clear(&r); high = secp256k1_scalar_is_high(sigs); secp256k1_scalar_cond_negate(sigs, high); diff --git a/src/secp256k1/src/ecmult_gen.h b/src/secp256k1/src/ecmult_gen.h index 8bc4f14c31..770b2cb21a 100644 --- a/src/secp256k1/src/ecmult_gen.h +++ b/src/secp256k1/src/ecmult_gen.h @@ -137,7 +137,8 @@ static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context* 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_gej(const secp256k1_ecmult_gen_context* ctx, secp256k1_gej *r, const secp256k1_scalar *a); +static void secp256k1_ecmult_gen_ge(const secp256k1_ecmult_gen_context* ctx, secp256k1_ge *r, const secp256k1_scalar *a); static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const secp256k1_hash_ctx *hash_ctx, const unsigned char *seed32); diff --git a/src/secp256k1/src/ecmult_gen_impl.h b/src/secp256k1/src/ecmult_gen_impl.h index 5a954977eb..a7a6d34d71 100644 --- a/src/secp256k1/src/ecmult_gen_impl.h +++ b/src/secp256k1/src/ecmult_gen_impl.h @@ -51,7 +51,7 @@ static void secp256k1_ecmult_gen_scalar_diff(secp256k1_scalar* diff) { secp256k1_scalar_add(diff, diff, &neghalf); } -static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context *ctx, secp256k1_gej *r, const secp256k1_scalar *gn) { +static void secp256k1_ecmult_gen_gej(const secp256k1_ecmult_gen_context *ctx, secp256k1_gej *r, const secp256k1_scalar *gn) { uint32_t comb_off; secp256k1_ge add; secp256k1_fe neg; @@ -281,11 +281,19 @@ static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context *ctx, secp25 secp256k1_memclear_explicit(&recoded, sizeof(recoded)); } +SECP256K1_INLINE static void secp256k1_ecmult_gen_ge(const secp256k1_ecmult_gen_context *ctx, secp256k1_ge *r, const secp256k1_scalar *a) { + secp256k1_gej rj; + secp256k1_ecmult_gen_gej(ctx, &rj, a); + secp256k1_ge_set_gej(r, &rj); + /* Jacobian coordinates resulting from our multiplication algorithm could potentially leak + * information about the secret input scalar, so clear the memory out to be on the safe side. */ + secp256k1_gej_clear(&rj); +} + /* Setup blinding values for secp256k1_ecmult_gen. */ 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; secp256k1_fe f; unsigned char nonce32[32]; secp256k1_rfc6979_hmac_sha256 rng; @@ -325,15 +333,13 @@ static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const * which secp256k1_gej_add_ge cannot handle. */ secp256k1_scalar_cmov(&b, &secp256k1_scalar_one, secp256k1_scalar_is_zero(&b)); secp256k1_rfc6979_hmac_sha256_finalize(&rng); - secp256k1_ecmult_gen(ctx, &gb, &b); + secp256k1_ecmult_gen_ge(ctx, &ctx->ge_offset, &b); secp256k1_scalar_negate(&b, &b); secp256k1_scalar_add(&ctx->scalar_offset, &b, &diff); - secp256k1_ge_set_gej(&ctx->ge_offset, &gb); /* Clean up. */ secp256k1_memclear_explicit(nonce32, sizeof(nonce32)); secp256k1_scalar_clear(&b); - secp256k1_gej_clear(&gb); secp256k1_fe_clear(&f); secp256k1_rfc6979_hmac_sha256_clear(&rng); } diff --git a/src/secp256k1/src/field.h b/src/secp256k1/src/field.h index 945029ecd8..8b25d99b66 100644 --- a/src/secp256k1/src/field.h +++ b/src/secp256k1/src/field.h @@ -166,7 +166,7 @@ static int secp256k1_fe_is_odd(const secp256k1_fe *a); /** Determine whether two field elements are equal. * * On input, a and b must be valid field elements with magnitudes not exceeding - * 1 and 31, respectively. + * 1 and 30, respectively. * Returns a = b (mod p). */ static int secp256k1_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b); diff --git a/src/secp256k1/src/field_5x52_impl.h b/src/secp256k1/src/field_5x52_impl.h index 3a976135eb..0e0e2d652a 100644 --- a/src/secp256k1/src/field_5x52_impl.h +++ b/src/secp256k1/src/field_5x52_impl.h @@ -338,11 +338,11 @@ SECP256K1_INLINE static void secp256k1_fe_impl_add(secp256k1_fe *r, const secp25 r->n[4] += a->n[4]; } -SECP256K1_INLINE static void secp256k1_fe_impl_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) { +SECP256K1_FORCE_INLINE static void secp256k1_fe_impl_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) { secp256k1_fe_mul_inner(r->n, a->n, b->n); } -SECP256K1_INLINE static void secp256k1_fe_impl_sqr(secp256k1_fe *r, const secp256k1_fe *a) { +SECP256K1_FORCE_INLINE static void secp256k1_fe_impl_sqr(secp256k1_fe *r, const secp256k1_fe *a) { secp256k1_fe_sqr_inner(r->n, a->n); } diff --git a/src/secp256k1/src/field_5x52_int128_impl.h b/src/secp256k1/src/field_5x52_int128_impl.h index f23f8ee1c4..8d1977b271 100644 --- a/src/secp256k1/src/field_5x52_int128_impl.h +++ b/src/secp256k1/src/field_5x52_int128_impl.h @@ -15,7 +15,7 @@ #define VERIFY_BITS(x, n) VERIFY_CHECK(((x) >> (n)) == 0) #define VERIFY_BITS_128(x, n) VERIFY_CHECK(secp256k1_u128_check_bits((x), (n))) -SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t *a, const uint64_t * SECP256K1_RESTRICT b) { +SECP256K1_FORCE_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t *a, const uint64_t * SECP256K1_RESTRICT b) { secp256k1_uint128 c, d; uint64_t t3, t4, tx, u0; uint64_t a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4]; @@ -151,7 +151,7 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t /* [r4 r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ } -SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint64_t *r, const uint64_t *a) { +SECP256K1_FORCE_INLINE static void secp256k1_fe_sqr_inner(uint64_t *r, const uint64_t *a) { secp256k1_uint128 c, d; uint64_t a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4]; uint64_t t3, t4, tx, u0; diff --git a/src/secp256k1/src/field_impl.h b/src/secp256k1/src/field_impl.h index 7aa7de431a..19af6aa26f 100644 --- a/src/secp256k1/src/field_impl.h +++ b/src/secp256k1/src/field_impl.h @@ -27,7 +27,7 @@ SECP256K1_INLINE static int secp256k1_fe_equal(const secp256k1_fe *a, const secp SECP256K1_FE_VERIFY(a); SECP256K1_FE_VERIFY(b); SECP256K1_FE_VERIFY_MAGNITUDE(a, 1); - SECP256K1_FE_VERIFY_MAGNITUDE(b, 31); + SECP256K1_FE_VERIFY_MAGNITUDE(b, 30); secp256k1_fe_negate(&na, a, 1); secp256k1_fe_add(&na, b); diff --git a/src/secp256k1/src/modules/ecdh/Makefile.am.include b/src/secp256k1/src/modules/ecdh/Makefile.am.include index 1866053529..81bc627917 100644 --- a/src/secp256k1/src/modules/ecdh/Makefile.am.include +++ b/src/secp256k1/src/modules/ecdh/Makefile.am.include @@ -1,5 +1,6 @@ include_HEADERS += include/secp256k1_ecdh.h noinst_HEADERS += src/modules/ecdh/main_impl.h noinst_HEADERS += src/modules/ecdh/tests_impl.h +noinst_HEADERS += src/modules/ecdh/tests_exhaustive_impl.h noinst_HEADERS += src/modules/ecdh/bench_impl.h noinst_HEADERS += src/wycheproof/ecdh_secp256k1_test.h diff --git a/src/secp256k1/src/modules/ecdh/tests_exhaustive_impl.h b/src/secp256k1/src/modules/ecdh/tests_exhaustive_impl.h new file mode 100644 index 0000000000..2bcd243493 --- /dev/null +++ b/src/secp256k1/src/modules/ecdh/tests_exhaustive_impl.h @@ -0,0 +1,56 @@ +/*********************************************************************** + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_ECDH_TESTS_EXHAUSTIVE_H +#define SECP256K1_MODULE_ECDH_TESTS_EXHAUSTIVE_H + +#include "../../../include/secp256k1_ecdh.h" +#include "main_impl.h" + +static void test_exhaustive_ecdh(const secp256k1_context *ctx, const secp256k1_ge *group) { + int i, j; + unsigned char seckeys[EXHAUSTIVE_TEST_ORDER - 1][32]; + secp256k1_pubkey pubkeys[EXHAUSTIVE_TEST_ORDER - 1]; + + /* Construct key pairs (32-byte secret key, public key object) for the entire group. */ + for (i = 1; i < EXHAUSTIVE_TEST_ORDER; i++) { + secp256k1_scalar scalar; + secp256k1_scalar_set_int(&scalar, i); + secp256k1_scalar_get_b32(seckeys[i - 1], &scalar); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkeys[i - 1], seckeys[i - 1])); + } + + /* Loop over key combinations. */ + for (i = 1; i < EXHAUSTIVE_TEST_ORDER; i++) { + for (j = 1; j < EXHAUSTIVE_TEST_ORDER; j++) { + unsigned char ecdh_result_ij[32]; + unsigned char ecdh_result_ji[32]; + + /* Calculate ECDH(i*G, j) and ECDH(j*G, i) using API function and verify that the results match. */ + CHECK(secp256k1_ecdh(ctx, ecdh_result_ij, &pubkeys[i - 1], seckeys[j - 1], NULL, NULL)); + CHECK(secp256k1_ecdh(ctx, ecdh_result_ji, &pubkeys[j - 1], seckeys[i - 1], NULL, NULL)); + CHECK(secp256k1_memcmp_var(ecdh_result_ij, ecdh_result_ji, 32) == 0); + + /* Recalculate the expected ECDH result manually by invoking the default ECDH hash + * function on the precomputed group element (group[i * j]) coordinates, and verify + * that it matches the previously calculated public API results. */ + { + secp256k1_ge ecdh_ge_expected = group[(i * j) % EXHAUSTIVE_TEST_ORDER]; + unsigned char ecdh_result_expected[32]; + unsigned char x[32]; + unsigned char y[32]; + + secp256k1_fe_normalize_var(&ecdh_ge_expected.x); + secp256k1_fe_normalize_var(&ecdh_ge_expected.y); + secp256k1_fe_get_b32(x, &ecdh_ge_expected.x); + secp256k1_fe_get_b32(y, &ecdh_ge_expected.y); + CHECK(secp256k1_ecdh_hash_function_default(ecdh_result_expected, x, y, NULL)); + CHECK(secp256k1_memcmp_var(ecdh_result_ij, ecdh_result_expected, 32) == 0); + } + } + } +} + +#endif diff --git a/src/secp256k1/src/modules/ecdsa_adaptor/dleq_impl.h b/src/secp256k1/src/modules/ecdsa_adaptor/dleq_impl.h index e38562a571..49e2ba9771 100644 --- a/src/secp256k1/src/modules/ecdsa_adaptor/dleq_impl.h +++ b/src/secp256k1/src/modules/ecdsa_adaptor/dleq_impl.h @@ -82,9 +82,12 @@ static void secp256k1_dleq_challenge(const secp256k1_hash_ctx *hash_ctx, secp256 static void secp256k1_dleq_pair(const secp256k1_ecmult_gen_context *ecmult_gen_ctx, secp256k1_ge *p, const secp256k1_scalar *sk, const secp256k1_ge *gen2) { secp256k1_gej pj[2]; - secp256k1_ecmult_gen(ecmult_gen_ctx, &pj[0], sk); + secp256k1_ecmult_gen_gej(ecmult_gen_ctx, &pj[0], sk); secp256k1_ecmult_const(&pj[1], gen2, sk); secp256k1_ge_set_all_gej(p, pj, 2); + + secp256k1_gej_clear(&pj[0]); + secp256k1_gej_clear(&pj[1]); } /* Generates a proof that the discrete logarithm of P1 to the secp256k1 base G is the diff --git a/src/secp256k1/src/modules/ecdsa_adaptor/main_impl.h b/src/secp256k1/src/modules/ecdsa_adaptor/main_impl.h index ce5611d007..1d5b954905 100644 --- a/src/secp256k1/src/modules/ecdsa_adaptor/main_impl.h +++ b/src/secp256k1/src/modules/ecdsa_adaptor/main_impl.h @@ -196,10 +196,13 @@ int secp256k1_ecdsa_adaptor_encrypt(const secp256k1_context* ctx, unsigned char /* R := k*Y */ secp256k1_ecmult_const(&rj[0], &enckey_ge, &k); /* R' := k*G */ - secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &rj[1], &k); + secp256k1_ecmult_gen_gej(&ctx->ecmult_gen_ctx, &rj[1], &k); secp256k1_ge_set_all_gej(r, rj, 2); + secp256k1_gej_clear(&rj[0]); + secp256k1_gej_clear(&rj[1]); + /* We declassify the non-secret nonce values to allow using them as branch points. */ secp256k1_declassify(ctx, &r[0], sizeof(r[0])); secp256k1_declassify(ctx, &r[1], sizeof(r[1])); @@ -325,7 +328,6 @@ int secp256k1_ecdsa_adaptor_recover(const secp256k1_context* ctx, unsigned char secp256k1_scalar deckey; secp256k1_ge enckey_expected_ge; secp256k1_ge enckey_ge; - secp256k1_gej enckey_expected_gej; unsigned char enckey33[33]; unsigned char enckey_expected33[33]; int ret = 1; @@ -349,8 +351,7 @@ int secp256k1_ecdsa_adaptor_recover(const secp256k1_context* ctx, unsigned char secp256k1_scalar_mul(&deckey, &deckey, &sp); /* Deal with ECDSA malleability */ - secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &enckey_expected_gej, &deckey); - secp256k1_ge_set_gej(&enckey_expected_ge, &enckey_expected_gej); + secp256k1_ecmult_gen_ge(&ctx->ecmult_gen_ctx, &enckey_expected_ge, &deckey); /* We declassify non-secret enckey_expected_ge to allow using it as a * branch point. */ secp256k1_declassify(ctx, &enckey_expected_ge, sizeof(enckey_expected_ge)); diff --git a/src/secp256k1/src/modules/ecdsa_adaptor/tests_impl.h b/src/secp256k1/src/modules/ecdsa_adaptor/tests_impl.h index 693cc7ddef..3ed0156820 100644 --- a/src/secp256k1/src/modules/ecdsa_adaptor/tests_impl.h +++ b/src/secp256k1/src/modules/ecdsa_adaptor/tests_impl.h @@ -12,11 +12,9 @@ static void rand_scalar(secp256k1_scalar *scalar) { static void rand_point(secp256k1_ge *point) { secp256k1_scalar x; - secp256k1_gej pointj; rand_scalar(&x); - secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &pointj, &x); - secp256k1_ge_set_gej(point, &pointj); + secp256k1_ecmult_gen_ge(&CTX->ecmult_gen_ctx, point, &x); } static void dleq_nonce_bitflip(unsigned char **args, size_t n_flip, size_t n_bytes) { diff --git a/src/secp256k1/src/modules/ecdsa_s2c/main_impl.h b/src/secp256k1/src/modules/ecdsa_s2c/main_impl.h index d8d8538450..d99577738b 100644 --- a/src/secp256k1/src/modules/ecdsa_s2c/main_impl.h +++ b/src/secp256k1/src/modules/ecdsa_s2c/main_impl.h @@ -146,7 +146,6 @@ int secp256k1_ecdsa_anti_exfil_host_commit(const secp256k1_context* ctx, unsigne int secp256k1_ecdsa_anti_exfil_signer_commit(const secp256k1_context* ctx, secp256k1_ecdsa_s2c_opening* opening, const unsigned char* msg32, const unsigned char* seckey32, const unsigned char* rand_commitment32) { unsigned char nonce32[32]; secp256k1_scalar k; - secp256k1_gej rj; secp256k1_ge r; unsigned int count = 0; int is_nonce_valid = 0; @@ -170,11 +169,9 @@ int secp256k1_ecdsa_anti_exfil_signer_commit(const secp256k1_context* ctx, secp2 count++; } - secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &rj, &k); - secp256k1_ge_set_gej(&r, &rj); + secp256k1_ecmult_gen_ge(&ctx->ecmult_gen_ctx, &r, &k); secp256k1_ecdsa_s2c_opening_save(opening, &r); secp256k1_memclear_explicit(nonce32, 32); - secp256k1_scalar_clear(&k); return 1; } diff --git a/src/secp256k1/src/modules/generator/main_impl.h b/src/secp256k1/src/modules/generator/main_impl.h index c2a1adff61..ec9484a9b1 100644 --- a/src/secp256k1/src/modules/generator/main_impl.h +++ b/src/secp256k1/src/modules/generator/main_impl.h @@ -217,7 +217,7 @@ static int secp256k1_generator_generate_internal(const secp256k1_context* ctx, s secp256k1_scalar blind; secp256k1_scalar_set_b32(&blind, blind32, &overflow); ret = !overflow; - secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &accum, &blind); + secp256k1_ecmult_gen_gej(&ctx->ecmult_gen_ctx, &accum, &blind); } secp256k1_sha256_initialize(&sha256); @@ -243,6 +243,8 @@ static int secp256k1_generator_generate_internal(const secp256k1_context* ctx, s secp256k1_gej_add_ge(&accum, &accum, &add); secp256k1_ge_set_gej(&add, &accum); + secp256k1_gej_clear(&accum); + secp256k1_generator_save(gen, &add); return ret; } diff --git a/src/secp256k1/src/modules/generator/pedersen_impl.h b/src/secp256k1/src/modules/generator/pedersen_impl.h index 7d2a8a2757..eee12557ea 100644 --- a/src/secp256k1/src/modules/generator/pedersen_impl.h +++ b/src/secp256k1/src/modules/generator/pedersen_impl.h @@ -41,7 +41,7 @@ static void secp256k1_pedersen_ecmult_small(secp256k1_gej *r, uint64_t gn, const /* sec * G + value * G2. */ SECP256K1_INLINE static void secp256k1_pedersen_ecmult(const secp256k1_ecmult_gen_context *ecmult_gen_ctx, secp256k1_gej *rj, const secp256k1_scalar *sec, uint64_t value, const secp256k1_ge* genp) { secp256k1_gej vj; - secp256k1_ecmult_gen(ecmult_gen_ctx, rj, sec); + secp256k1_ecmult_gen_gej(ecmult_gen_ctx, rj, sec); secp256k1_pedersen_ecmult_small(&vj, value, genp); /* FIXME: constant time. */ secp256k1_gej_add_var(rj, rj, &vj, NULL); diff --git a/src/secp256k1/src/modules/musig/session_impl.h b/src/secp256k1/src/modules/musig/session_impl.h index a66580d994..680e3e110d 100644 --- a/src/secp256k1/src/modules/musig/session_impl.h +++ b/src/secp256k1/src/modules/musig/session_impl.h @@ -415,7 +415,7 @@ static int secp256k1_musig_nonce_gen_internal(const secp256k1_context* ctx, secp /* Compute pubnonce as two gejs */ for (i = 0; i < 2; i++) { - secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &nonce_ptj[i], &k[i]); + secp256k1_ecmult_gen_gej(&ctx->ecmult_gen_ctx, &nonce_ptj[i], &k[i]); secp256k1_scalar_clear(&k[i]); } diff --git a/src/secp256k1/src/modules/musig/tests_impl.h b/src/secp256k1/src/modules/musig/tests_impl.h index 76b2c06bf7..acf45bec2d 100644 --- a/src/secp256k1/src/modules/musig/tests_impl.h +++ b/src/secp256k1/src/modules/musig/tests_impl.h @@ -381,7 +381,7 @@ static void musig_api_tests(void) { secp256k1_ge aggnonce_pt[2]; secp256k1_musig_aggnonce_load(CTX, aggnonce_pt, &aggnonce); for (i = 0; i < 2; i++) { - secp256k1_ge_is_infinity(&aggnonce_pt[i]); + CHECK(secp256k1_ge_is_infinity(&aggnonce_pt[i]) == 1); } } CHECK(secp256k1_musig_nonce_agg(CTX, &aggnonce, pubnonce_ptr, 2) == 1); diff --git a/src/secp256k1/src/modules/rangeproof/borromean_impl.h b/src/secp256k1/src/modules/rangeproof/borromean_impl.h index cd62abaaeb..eb88f37a43 100644 --- a/src/secp256k1/src/modules/rangeproof/borromean_impl.h +++ b/src/secp256k1/src/modules/rangeproof/borromean_impl.h @@ -129,9 +129,8 @@ int secp256k1_borromean_sign(const secp256k1_hash_ctx *hash_ctx, const secp256k1 count = 0; for (i = 0; i < nrings; i++) { VERIFY_CHECK(INT_MAX - count > rsizes[i]); - secp256k1_ecmult_gen(ecmult_gen_ctx, &rgej, &k[i]); - secp256k1_ge_set_gej(&rge, &rgej); - if (secp256k1_gej_is_infinity(&rgej)) { + secp256k1_ecmult_gen_ge(ecmult_gen_ctx, &rge, &k[i]); + if (secp256k1_ge_is_infinity(&rge)) { return 0; } secp256k1_eckey_pubkey_serialize33(&rge, tmp); diff --git a/src/secp256k1/src/modules/rangeproof/tests_impl.h b/src/secp256k1/src/modules/rangeproof/tests_impl.h index 002c3707e7..85c97c54d8 100644 --- a/src/secp256k1/src/modules/rangeproof/tests_impl.h +++ b/src/secp256k1/src/modules/rangeproof/tests_impl.h @@ -162,7 +162,7 @@ static void test_borromean_internal(void) { s[i] = one; } if (j == secidx[i]) { - secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &pubs[c + j], &sec[i]); + secp256k1_ecmult_gen_gej(&CTX->ecmult_gen_ctx, &pubs[c + j], &sec[i]); } else { testutil_random_ge_test(&ge); testutil_random_ge_jacobian_test(&pubs[c + j],&ge); @@ -811,35 +811,6 @@ static void test_rangeproof_fixed_vectors(void) { } } -static void print_vector_helper(unsigned char *buf, size_t buf_len) { - size_t j; - printf(" "); - for (j = 0; j < buf_len; j++) { - printf("0x%02x", buf[j]); - if (j == buf_len-1) { - printf(",\n"); - } else if ((j+1) % 16 != 0) { - printf(", "); - } else { - printf(",\n"); - printf(" "); - } - } - printf("};\n"); -} - -static void print_vector(int i, unsigned char *proof, size_t p_len, secp256k1_pedersen_commitment *commit) { - unsigned char commit_output[33]; - - printf("unsigned char vector_%d[] = {\n", i); - print_vector_helper(proof, p_len); - - CHECK(secp256k1_pedersen_commitment_serialize(CTX, commit_output, commit)); - printf("unsigned char commit_%d[] = {\n", i); - print_vector_helper(commit_output, sizeof(commit_output)); -} - - /* Use same nonce and blinding value for all "reproducible" test vectors */ static unsigned char vector_blind[] = { 0x48, 0x26, 0xad, 0x41, 0x37, 0x4c, 0x25, 0x62, 0x52, 0x14, 0x78, 0x82, 0x89, 0x9c, 0x86, 0x27, @@ -1233,8 +1204,6 @@ static void test_rangeproof_fixed_vectors_reproducible(void) { CHECK(secp256k1_rangeproof_sign(CTX, proof, &p_len, min_value, &pc, vector_blind, vector_nonce, exp, min_bits, value, message, m_len, NULL, 0, secp256k1_generator_h)); CHECK(p_len <= secp256k1_rangeproof_max_size(CTX, value, min_bits)); CHECK(p_len == sizeof(proof)); - /* Uncomment the next line to print the test vector */ - /* print_vector(0, proof, p_len, &pc); */ CHECK(p_len == sizeof(vector_0)); CHECK(secp256k1_memcmp_var(proof, vector_0, p_len) == 0); @@ -1287,8 +1256,6 @@ static void test_rangeproof_fixed_vectors_reproducible(void) { CHECK(secp256k1_rangeproof_sign(CTX, proof, &p_len, min_value, &pc, vector_blind, vector_nonce, exp, min_bits, value, message, m_len, NULL, 0, secp256k1_generator_h)); CHECK(p_len <= secp256k1_rangeproof_max_size(CTX, value, min_bits)); CHECK(p_len == sizeof(proof)); - /* Uncomment the next line to print the test vector */ - /* print_vector(1, proof, p_len, &pc); */ CHECK(p_len == sizeof(vector_1)); CHECK(secp256k1_memcmp_var(proof, vector_1, p_len) == 0); @@ -1333,8 +1300,6 @@ static void test_rangeproof_fixed_vectors_reproducible(void) { CHECK(secp256k1_rangeproof_sign(CTX, proof, &p_len, min_value, &pc, vector_blind, vector_nonce, exp, min_bits, value, message, m_len, NULL, 0, secp256k1_generator_h)); CHECK(p_len <= secp256k1_rangeproof_max_size(CTX, value, min_bits)); CHECK(p_len == sizeof(proof)); - /* Uncomment the next line to print the test vector */ - /* print_vector(2, proof, p_len, &pc); */ CHECK(p_len == sizeof(vector_2)); CHECK(secp256k1_memcmp_var(proof, vector_2, p_len) == 0); diff --git a/src/secp256k1/src/modules/schnorrsig/main_impl.h b/src/secp256k1/src/modules/schnorrsig/main_impl.h index 5100557f4d..efc7216546 100644 --- a/src/secp256k1/src/modules/schnorrsig/main_impl.h +++ b/src/secp256k1/src/modules/schnorrsig/main_impl.h @@ -123,7 +123,6 @@ static int secp256k1_schnorrsig_sign_internal(const secp256k1_context* ctx, unsi secp256k1_scalar sk; secp256k1_scalar e; secp256k1_scalar k; - secp256k1_gej rj; secp256k1_ge pk; secp256k1_ge r; unsigned char nonce32[32] = { 0 }; @@ -160,8 +159,7 @@ static int secp256k1_schnorrsig_sign_internal(const secp256k1_context* ctx, unsi ret &= !secp256k1_scalar_is_zero(&k); secp256k1_scalar_cmov(&k, &secp256k1_scalar_one, !ret); - secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &rj, &k); - secp256k1_ge_set_gej(&r, &rj); + secp256k1_ecmult_gen_ge(&ctx->ecmult_gen_ctx, &r, &k); /* We declassify r to allow using it as a branch point. This is fine * because r is not a secret. */ @@ -183,7 +181,6 @@ static int secp256k1_schnorrsig_sign_internal(const secp256k1_context* ctx, unsi secp256k1_scalar_clear(&sk); secp256k1_memclear_explicit(seckey, sizeof(seckey)); secp256k1_memclear_explicit(nonce32, sizeof(nonce32)); - secp256k1_gej_clear(&rj); return ret; } diff --git a/src/secp256k1/src/modules/schnorrsig_halfagg/main_impl.h b/src/secp256k1/src/modules/schnorrsig_halfagg/main_impl.h index 466c819b82..de5db25f51 100644 --- a/src/secp256k1/src/modules/schnorrsig_halfagg/main_impl.h +++ b/src/secp256k1/src/modules/schnorrsig_halfagg/main_impl.h @@ -189,7 +189,7 @@ int secp256k1_schnorrsig_aggverify(const secp256k1_context *ctx, const secp256k1 if (overflow) { return 0; } - secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &lhs, &s); + secp256k1_ecmult_gen_gej(&ctx->ecmult_gen_ctx, &lhs, &s); /* Check that lhs == rhs */ secp256k1_gej_neg(&lhs, &lhs); diff --git a/src/secp256k1/src/modules/surjection/main_impl.h b/src/secp256k1/src/modules/surjection/main_impl.h index 968cc4774c..80dbd7f316 100644 --- a/src/secp256k1/src/modules/surjection/main_impl.h +++ b/src/secp256k1/src/modules/surjection/main_impl.h @@ -337,7 +337,20 @@ int secp256k1_surjectionproof_generate(const secp256k1_context* ctx, secp256k1_s rsizes[0] = (int) n_used_pubkeys; indices[0] = (int) ring_input_index; secp256k1_surjection_genmessage(hash_ctx, msg32, ephemeral_input_tags, n_total_pubkeys, ephemeral_output_tag); - if (secp256k1_surjection_genrand(hash_ctx, borromean_s, n_used_pubkeys, &blinding_key) == 0) { + /* Derive every s-value, including the one used as the signing nonce, from + * every proof-relevant input to + * secp256k1_surjectionproof_generate. Except with negligible hash-collision + * probability, this prevents distinct proof inputs from reusing any + * s-value. + * + * The proof-relevant arguments to secp256k1_surjectionproof_generate + * correspond as follows: proof supplies n_total_pubkeys (proof->n_inputs), + * proof->used_inputs, and n_used_pubkeys, while proof->data is output and + * proof->initialized is VERIFY-only validation state; ephemeral_input_tags + * is committed by msg32; n_ephemeral_input_tags equals n_total_pubkeys as + * checked above; ephemeral_output_tag is committed by msg32; input_index + * and both blinding keys are passed directly. */ + if (secp256k1_surjection_genrand(hash_ctx, borromean_s, n_used_pubkeys, n_total_pubkeys, proof->used_inputs, msg32, input_index, input_blinding_key, output_blinding_key) == 0) { return 0; } /* Borromean sign will overwrite one of the s values we just generated, so use diff --git a/src/secp256k1/src/modules/surjection/surjection.h b/src/secp256k1/src/modules/surjection/surjection.h index ac7407d718..70b886ae98 100644 --- a/src/secp256k1/src/modules/surjection/surjection.h +++ b/src/secp256k1/src/modules/surjection/surjection.h @@ -12,7 +12,7 @@ SECP256K1_INLINE static int secp256k1_surjection_genmessage(unsigned char *msg32, secp256k1_ge *ephemeral_input_tags, size_t n_input_tags, secp256k1_ge *ephemeral_output_tag); -SECP256K1_INLINE static int secp256k1_surjection_genrand(secp256k1_scalar *s, size_t ns, const secp256k1_scalar *blinding_key); +SECP256K1_INLINE static int secp256k1_surjection_genrand(const secp256k1_hash_ctx *hash_ctx, secp256k1_scalar *s, size_t ns, size_t n_inputs, const unsigned char *used_inputs, const unsigned char *msg32, size_t input_index, const unsigned char *input_blinding_key, const unsigned char *output_blinding_key); SECP256K1_INLINE static int secp256k1_surjection_compute_public_keys(secp256k1_gej *pubkeys, size_t n_pubkeys, const secp256k1_ge *input_tags, size_t n_input_tags, const unsigned char *used_tags, const secp256k1_ge *output_tag, size_t input_index, size_t *ring_input_index); diff --git a/src/secp256k1/src/modules/surjection/surjection_impl.h b/src/secp256k1/src/modules/surjection/surjection_impl.h index bccced522b..cdf7714bf4 100644 --- a/src/secp256k1/src/modules/surjection/surjection_impl.h +++ b/src/secp256k1/src/modules/surjection/surjection_impl.h @@ -35,31 +35,52 @@ SECP256K1_INLINE static void secp256k1_surjection_genmessage(const secp256k1_has secp256k1_sha256_clear(&sha256_en); } -SECP256K1_INLINE static int secp256k1_surjection_genrand(const secp256k1_hash_ctx *hash_ctx, secp256k1_scalar *s, size_t ns, const secp256k1_scalar *blinding_key) { +/* Derive the ring's s-values, one of which is used as the signing nonce, from a + * seed that hashes the passed-in arguments. See the call site for how these + * correspond to the proof inputs. */ +SECP256K1_INLINE static int secp256k1_surjection_genrand(const secp256k1_hash_ctx *hash_ctx, secp256k1_scalar *s, size_t ns, size_t n_inputs, const unsigned char *used_inputs, const unsigned char *msg32, size_t input_index, const unsigned char *input_blinding_key, const unsigned char *output_blinding_key) { size_t i; - unsigned char sec_input[36]; + size_t used_inputs_len; + unsigned char n_inputs_ser[4]; + unsigned char index_ser[4]; + unsigned char counter[4]; + unsigned char seed[32]; + unsigned char out[32]; secp256k1_sha256 sha256_en; + used_inputs_len = (n_inputs + 7) / 8; + secp256k1_write_be32(n_inputs_ser, (uint32_t)n_inputs); + secp256k1_write_be32(index_ser, (uint32_t)input_index); + + /* Hash the arguments into the seed. */ + secp256k1_sha256_initialize(&sha256_en); + secp256k1_sha256_write(hash_ctx, &sha256_en, n_inputs_ser, 4); + secp256k1_sha256_write(hash_ctx, &sha256_en, used_inputs, used_inputs_len); + secp256k1_sha256_write(hash_ctx, &sha256_en, msg32, 32); + secp256k1_sha256_write(hash_ctx, &sha256_en, index_ser, 4); + secp256k1_sha256_write(hash_ctx, &sha256_en, input_blinding_key, 32); + secp256k1_sha256_write(hash_ctx, &sha256_en, output_blinding_key, 32); + secp256k1_sha256_finalize(hash_ctx, &sha256_en, seed); + secp256k1_sha256_clear(&sha256_en); + /* compute s values */ - secp256k1_scalar_get_b32(&sec_input[4], blinding_key); for (i = 0; i < ns; i++) { int overflow = 0; - sec_input[0] = i; - sec_input[1] = i >> 8; - sec_input[2] = i >> 16; - sec_input[3] = i >> 24; - + secp256k1_write_be32(counter, (uint32_t)i); secp256k1_sha256_initialize(&sha256_en); - secp256k1_sha256_write(hash_ctx, &sha256_en, sec_input, 36); - secp256k1_sha256_finalize(hash_ctx, &sha256_en, sec_input); + secp256k1_sha256_write(hash_ctx, &sha256_en, counter, 4); + secp256k1_sha256_write(hash_ctx, &sha256_en, seed, 32); + secp256k1_sha256_finalize(hash_ctx, &sha256_en, out); secp256k1_sha256_clear(&sha256_en); - secp256k1_scalar_set_b32(&s[i], sec_input, &overflow); + secp256k1_scalar_set_b32(&s[i], out, &overflow); if (overflow == 1) { - secp256k1_memclear_explicit(sec_input, 32); + secp256k1_memclear_explicit(out, sizeof(out)); + secp256k1_memclear_explicit(seed, sizeof(seed)); return 0; } } - secp256k1_memclear_explicit(sec_input, 32); + secp256k1_memclear_explicit(out, sizeof(out)); + secp256k1_memclear_explicit(seed, sizeof(seed)); return 1; } diff --git a/src/secp256k1/src/modules/surjection/tests_impl.h b/src/secp256k1/src/modules/surjection/tests_impl.h index 7ba328c326..0680a2abe2 100644 --- a/src/secp256k1/src/modules/surjection/tests_impl.h +++ b/src/secp256k1/src/modules/surjection/tests_impl.h @@ -643,6 +643,147 @@ static void test_gen_verify_all(void) { test_gen_verify(SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS, SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS); } +static int surjection_genrand_streams_equal(const secp256k1_scalar *a, const secp256k1_scalar *b, size_t n) { + size_t i; + for (i = 0; i < n; i++) { + if (!secp256k1_scalar_eq(&a[i], &b[i])) { + return 0; + } + } + return 1; +} + +static int surjection_genrand_stream_all_differ(const secp256k1_scalar *a, const secp256k1_scalar *b, size_t n) { + size_t i; + for (i = 0; i < n; i++) { + if (secp256k1_scalar_eq(&a[i], &b[i])) { + return 0; + } + } + return 1; +} + +/* Test that changing any proof-relevant argument to + * secp256k1_surjectionproof_generate changes every s-value produced by + * secp256k1_surjection_genrand. */ +static void test_surjection_genrand(void) { + const secp256k1_hash_ctx *hash_ctx = secp256k1_get_hash_context(CTX); + const size_t ns = 4; + const size_t n_inputs = 5; + unsigned char msg_a[32]; + unsigned char msg_b[32]; + unsigned char ikey_a[32]; + unsigned char ikey_b[32]; + unsigned char okey_a[32]; + unsigned char okey_b[32]; + unsigned char used_a[SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS / 8] = { 0 }; + unsigned char used_b[SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS / 8] = { 0 }; + secp256k1_scalar s_base[4]; + secp256k1_scalar s_cmp[4]; + + /* Baseline inputs, plus a one-bit variant of each. */ + testrand256(msg_a); + memcpy(msg_b, msg_a, 32); + msg_b[0] ^= 0x01; + testrand256(ikey_a); + memcpy(ikey_b, ikey_a, 32); + ikey_b[0] ^= 0x01; + testrand256(okey_a); + memcpy(okey_b, okey_a, 32); + okey_b[0] ^= 0x01; + + /* Two used-input bitmaps with the same popcount but a different set. */ + used_a[0] = 0x0f; /* inputs {0,1,2,3} */ + used_b[0] = 0x17; /* inputs {0,1,2,4} */ + + /* Baseline. */ + CHECK(secp256k1_surjection_genrand(hash_ctx, s_base, ns, n_inputs, used_a, msg_a, 0, ikey_a, okey_a) == 1); + + /* Determinism: identical arguments reproduce the identical stream. */ + CHECK(secp256k1_surjection_genrand(hash_ctx, s_cmp, ns, n_inputs, used_a, msg_a, 0, ikey_a, okey_a) == 1); + CHECK(surjection_genrand_streams_equal(s_base, s_cmp, ns)); + + /* The message is bound. */ + CHECK(secp256k1_surjection_genrand(hash_ctx, s_cmp, ns, n_inputs, used_a, msg_b, 0, ikey_a, okey_a) == 1); + CHECK(surjection_genrand_stream_all_differ(s_base, s_cmp, ns)); + + /* The used-input selection is bound. */ + CHECK(secp256k1_surjection_genrand(hash_ctx, s_cmp, ns, n_inputs, used_b, msg_a, 0, ikey_a, okey_a) == 1); + CHECK(surjection_genrand_stream_all_differ(s_base, s_cmp, ns)); + + /* The total input count is bound even at the same bitmap byte length: + * n_inputs = 8 and n_inputs = 5 both use a one-byte bitmap. */ + CHECK(secp256k1_surjection_genrand(hash_ctx, s_cmp, ns, 8, used_a, msg_a, 0, ikey_a, okey_a) == 1); + CHECK(surjection_genrand_stream_all_differ(s_base, s_cmp, ns)); + + /* The honest input index is bound. */ + CHECK(secp256k1_surjection_genrand(hash_ctx, s_cmp, ns, n_inputs, used_a, msg_a, 1, ikey_a, okey_a) == 1); + CHECK(surjection_genrand_stream_all_differ(s_base, s_cmp, ns)); + + /* The input blinding key is bound. */ + CHECK(secp256k1_surjection_genrand(hash_ctx, s_cmp, ns, n_inputs, used_a, msg_a, 0, ikey_b, okey_a) == 1); + CHECK(surjection_genrand_stream_all_differ(s_base, s_cmp, ns)); + + /* The output blinding key is bound. */ + CHECK(secp256k1_surjection_genrand(hash_ctx, s_cmp, ns, n_inputs, used_a, msg_a, 0, ikey_a, okey_b) == 1); + CHECK(surjection_genrand_stream_all_differ(s_base, s_cmp, ns)); +} + +/* Changing an unused input tag changes the proof message. Check that every + * s-value changes and that both proofs verify. */ +static void test_surjectionproof_generate_changes_s_values(void) { + const size_t n_inputs = 3; + const size_t n_used = 2; + unsigned char seed[32]; + unsigned char input_blinding_key[3][32] = {{ 0 }}; + unsigned char output_blinding_key[32] = { 0 }; + unsigned char reblind[32] = { 0 }; + secp256k1_fixed_asset_tag fixed_input_tags[3]; + secp256k1_generator ephemeral_input_tags[3]; + secp256k1_generator ephemeral_output_tag; + secp256k1_surjectionproof proof_a; + secp256k1_surjectionproof proof_b; + size_t input_index; + size_t unused_index = n_inputs; + size_t i; + + testrand256(seed); + for (i = 0; i < n_inputs; i++) { + testrand256(fixed_input_tags[i].data); + input_blinding_key[i][31] = (unsigned char)i + 1; + CHECK(secp256k1_generator_generate_blinded(CTX, &ephemeral_input_tags[i], fixed_input_tags[i].data, input_blinding_key[i])); + } + output_blinding_key[31] = 4; + reblind[31] = 5; + CHECK(secp256k1_generator_generate_blinded(CTX, &ephemeral_output_tag, fixed_input_tags[1].data, output_blinding_key)); + + CHECK(secp256k1_surjectionproof_initialize(CTX, &proof_a, &input_index, fixed_input_tags, n_inputs, n_used, &fixed_input_tags[1], 100, seed) > 0); + CHECK(input_index == 1); + CHECK(secp256k1_surjectionproof_n_used_inputs(CTX, &proof_a) == n_used); + proof_b = proof_a; + + for (i = 0; i < n_inputs; i++) { + if (!(proof_a.used_inputs[i / 8] & (1 << (i % 8)))) { + unused_index = i; + } + } + CHECK(unused_index < n_inputs); + + CHECK(secp256k1_surjectionproof_generate(CTX, &proof_a, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, input_index, input_blinding_key[input_index], output_blinding_key) == 1); + CHECK(secp256k1_surjectionproof_verify(CTX, &proof_a, ephemeral_input_tags, n_inputs, &ephemeral_output_tag) == 1); + + /* Regenerate the unused ephemeral input tag with reblind instead of + * input_blinding_key[unused_index]. The modified tag is the only proof input + * that differs between the two secp256k1_surjectionproof_generate calls. */ + CHECK(secp256k1_generator_generate_blinded(CTX, &ephemeral_input_tags[unused_index], fixed_input_tags[unused_index].data, reblind)); + CHECK(secp256k1_surjectionproof_generate(CTX, &proof_b, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, input_index, input_blinding_key[input_index], output_blinding_key) == 1); + CHECK(secp256k1_surjectionproof_verify(CTX, &proof_b, ephemeral_input_tags, n_inputs, &ephemeral_output_tag) == 1); + + for (i = 0; i < n_used; i++) { + CHECK(secp256k1_memcmp_var(&proof_a.data[32 + 32 * i], &proof_b.data[32 + 32 * i], 32) != 0); + } +} + /* --- Test registry --- */ static const struct tf_test_entry tests_surjection[] = { CASE1(test_surjectionproof_api), @@ -651,6 +792,8 @@ static const struct tf_test_entry tests_surjection[] = { CASE1(test_input_selection_all), CASE1(test_input_selection_distribution), CASE1(test_gen_verify_all), + CASE1(test_surjection_genrand), + CASE1(test_surjectionproof_generate_changes_s_values), CASE1(test_no_used_inputs_verify), CASE1(test_bad_serialize), CASE1(test_bad_parse), diff --git a/src/secp256k1/src/modules/whitelist/whitelist_impl.h b/src/secp256k1/src/modules/whitelist/whitelist_impl.h index 9a9023fb82..f26c255c4a 100644 --- a/src/secp256k1/src/modules/whitelist/whitelist_impl.h +++ b/src/secp256k1/src/modules/whitelist/whitelist_impl.h @@ -61,8 +61,9 @@ static int secp256k1_whitelist_compute_tweaked_privkey(const secp256k1_context* } if (ret) { secp256k1_gej pkeyj; - secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pkeyj, skey); + secp256k1_ecmult_gen_gej(&ctx->ecmult_gen_ctx, &pkeyj, skey); ret = secp256k1_whitelist_hash_pubkey(hash_ctx, &tweak, &pkeyj); + secp256k1_gej_clear(&pkeyj); } if (ret) { secp256k1_scalar sonline; diff --git a/src/secp256k1/src/scalar.h b/src/secp256k1/src/scalar.h index 4dd20a692b..3de1de254d 100644 --- a/src/secp256k1/src/scalar.h +++ b/src/secp256k1/src/scalar.h @@ -22,10 +22,10 @@ /** Clear a scalar to prevent the leak of sensitive data. */ static void secp256k1_scalar_clear(secp256k1_scalar *r); -/** Access bits (1 < count <= 32) from a scalar. All requested bits must belong to the same 32-bit limb. */ +/** Access bits (1 <= count <= 32) from a scalar. All requested bits must belong to the same 32-bit limb. */ static uint32_t secp256k1_scalar_get_bits_limb32(const secp256k1_scalar *a, unsigned int offset, unsigned int count); -/** Access bits (1 < count <= 32) from a scalar. offset + count must be < 256. Not constant time in offset and count. */ +/** Access bits (1 <= count <= 32) from a scalar. offset + count must be <= 256. Not constant time in offset and count. */ static uint32_t secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count); /** Set a scalar from a big endian byte array. The scalar will be reduced modulo group order `n`. diff --git a/src/secp256k1/src/scalar_4x64_impl.h b/src/secp256k1/src/scalar_4x64_impl.h index 0f62ee7aff..6570e2a3b4 100644 --- a/src/secp256k1/src/scalar_4x64_impl.h +++ b/src/secp256k1/src/scalar_4x64_impl.h @@ -51,7 +51,8 @@ SECP256K1_INLINE static void secp256k1_scalar_set_u64(secp256k1_scalar *r, uint6 SECP256K1_INLINE static uint32_t secp256k1_scalar_get_bits_limb32(const secp256k1_scalar *a, unsigned int offset, unsigned int count) { SECP256K1_SCALAR_VERIFY(a); VERIFY_CHECK(count > 0 && count <= 32); - VERIFY_CHECK((offset + count - 1) >> 6 == offset >> 6); + VERIFY_CHECK(offset <= 256 - count); + VERIFY_CHECK((offset + count - 1) >> 5 == offset >> 5); return (a->d[offset >> 6] >> (offset & 0x3F)) & (0xFFFFFFFF >> (32 - count)); } @@ -59,12 +60,13 @@ SECP256K1_INLINE static uint32_t secp256k1_scalar_get_bits_limb32(const secp256k SECP256K1_INLINE static uint32_t secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count) { SECP256K1_SCALAR_VERIFY(a); VERIFY_CHECK(count > 0 && count <= 32); - VERIFY_CHECK(offset + count <= 256); + VERIFY_CHECK(offset <= 256 - count); if ((offset + count - 1) >> 6 == offset >> 6) { - return secp256k1_scalar_get_bits_limb32(a, offset, count); + return (a->d[offset >> 6] >> (offset & 0x3F)) & (0xFFFFFFFF >> (32 - count)); } else { VERIFY_CHECK((offset >> 6) + 1 < 4); + VERIFY_CHECK((offset & 0x3F) > 0); return ((a->d[offset >> 6] >> (offset & 0x3F)) | (a->d[(offset >> 6) + 1] << (64 - (offset & 0x3F)))) & (0xFFFFFFFF >> (32 - count)); } } diff --git a/src/secp256k1/src/scalar_8x32_impl.h b/src/secp256k1/src/scalar_8x32_impl.h index 11ae4b45f2..906039f383 100644 --- a/src/secp256k1/src/scalar_8x32_impl.h +++ b/src/secp256k1/src/scalar_8x32_impl.h @@ -69,6 +69,7 @@ SECP256K1_INLINE static void secp256k1_scalar_set_u64(secp256k1_scalar *r, uint6 SECP256K1_INLINE static uint32_t secp256k1_scalar_get_bits_limb32(const secp256k1_scalar *a, unsigned int offset, unsigned int count) { SECP256K1_SCALAR_VERIFY(a); VERIFY_CHECK(count > 0 && count <= 32); + VERIFY_CHECK(offset <= 256 - count); VERIFY_CHECK((offset + count - 1) >> 5 == offset >> 5); return (a->d[offset >> 5] >> (offset & 0x1F)) & (0xFFFFFFFF >> (32 - count)); @@ -77,7 +78,7 @@ SECP256K1_INLINE static uint32_t secp256k1_scalar_get_bits_limb32(const secp256k SECP256K1_INLINE static uint32_t secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count) { SECP256K1_SCALAR_VERIFY(a); VERIFY_CHECK(count > 0 && count <= 32); - VERIFY_CHECK(offset + count <= 256); + VERIFY_CHECK(offset <= 256 - count); if ((offset + count - 1) >> 5 == offset >> 5) { return secp256k1_scalar_get_bits_limb32(a, offset, count); diff --git a/src/secp256k1/src/scalar_low_impl.h b/src/secp256k1/src/scalar_low_impl.h index 6b401d3715..3c0119bf74 100644 --- a/src/secp256k1/src/scalar_low_impl.h +++ b/src/secp256k1/src/scalar_low_impl.h @@ -33,8 +33,10 @@ SECP256K1_INLINE static void secp256k1_scalar_set_u64(secp256k1_scalar *r, uint6 SECP256K1_INLINE static uint32_t secp256k1_scalar_get_bits_limb32(const secp256k1_scalar *a, unsigned int offset, unsigned int count) { SECP256K1_SCALAR_VERIFY(a); - VERIFY_CHECK(count > 0 && count <= 32); + VERIFY_CHECK(offset <= 256 - count); + VERIFY_CHECK((offset + count - 1) >> 5 == offset >> 5); + if (offset < 32) { return (*a >> offset) & (0xFFFFFFFF >> (32 - count)); } else { @@ -44,8 +46,14 @@ SECP256K1_INLINE static uint32_t secp256k1_scalar_get_bits_limb32(const secp256k SECP256K1_INLINE static uint32_t secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count) { SECP256K1_SCALAR_VERIFY(a); + VERIFY_CHECK(count > 0 && count <= 32); + VERIFY_CHECK(offset <= 256 - count); - return secp256k1_scalar_get_bits_limb32(a, offset, count); + if (offset < 32) { + return (*a >> offset) & (0xFFFFFFFF >> (32 - count)); + } else { + return 0; + } } SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scalar *a) { return *a >= EXHAUSTIVE_TEST_ORDER; } diff --git a/src/secp256k1/src/secp256k1.c b/src/secp256k1/src/secp256k1.c index a3d37bd213..b2852dc529 100644 --- a/src/secp256k1/src/secp256k1.c +++ b/src/secp256k1/src/secp256k1.c @@ -600,12 +600,10 @@ static int secp256k1_ecdsa_sign_inner(const secp256k1_context* ctx, secp256k1_sc secp256k1_declassify(ctx, &is_nonce_valid, sizeof(is_nonce_valid)); if (is_nonce_valid) { if (s2c_data32 != NULL) { - secp256k1_gej nonce_pj; secp256k1_ge nonce_p; /* Compute original nonce commitment/pubkey */ - secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &nonce_pj, &non); - secp256k1_ge_set_gej(&nonce_p, &nonce_pj); + secp256k1_ecmult_gen_ge(&ctx->ecmult_gen_ctx, &nonce_p, &non); if (s2c_opening != NULL) { secp256k1_ecdsa_s2c_opening_save(s2c_opening, &nonce_p); } @@ -675,15 +673,12 @@ int secp256k1_ec_seckey_verify(const secp256k1_context* ctx, const unsigned char } static int secp256k1_ec_pubkey_create_helper(const secp256k1_ecmult_gen_context *ecmult_gen_ctx, secp256k1_scalar *seckey_scalar, secp256k1_ge *p, const unsigned char *seckey) { - secp256k1_gej pj; int ret; ret = secp256k1_scalar_set_b32_seckey(seckey_scalar, seckey); secp256k1_scalar_cmov(seckey_scalar, &secp256k1_scalar_one, !ret); - secp256k1_ecmult_gen(ecmult_gen_ctx, &pj, seckey_scalar); - secp256k1_ge_set_gej(p, &pj); - secp256k1_gej_clear(&pj); + secp256k1_ecmult_gen_ge(ecmult_gen_ctx, p, seckey_scalar); return ret; } diff --git a/src/secp256k1/src/tests.c b/src/secp256k1/src/tests.c index 5d5e833d1f..ebc49c41ff 100644 --- a/src/secp256k1/src/tests.c +++ b/src/secp256k1/src/tests.c @@ -37,6 +37,11 @@ #include "int128_impl.h" #endif +#if defined(__GNUC__) +# pragma GCC diagnostic push +# pragma GCC diagnostic warning "-Wunused-function" +#endif + #define CONDITIONAL_TEST(cnt, nam) if (COUNT < (cnt)) { printf("Skipping %s (iteration count too low)\n", nam); } else static secp256k1_context *CTX = NULL; @@ -287,7 +292,6 @@ static void run_proper_context_tests(int use_prealloc) { void *my_ctx_prealloc = NULL; unsigned char seed[32] = {0x17}; - secp256k1_gej pubj; secp256k1_ge pub; secp256k1_scalar msg, key, nonce; secp256k1_scalar sigr, sigs; @@ -375,8 +379,7 @@ static void run_proper_context_tests(int use_prealloc) { /*** attempt to use them ***/ testutil_random_scalar_order_test(&msg); testutil_random_scalar_order_test(&key); - secp256k1_ecmult_gen(&my_ctx->ecmult_gen_ctx, &pubj, &key); - secp256k1_ge_set_gej(&pub, &pubj); + secp256k1_ecmult_gen_ge(&my_ctx->ecmult_gen_ctx, &pub, &key); /* obtain a working nonce */ do { @@ -415,7 +418,6 @@ static void run_scratch_tests(void) { size_t checkpoint; size_t checkpoint_2; secp256k1_scratch_space *scratch; - secp256k1_scratch_space local_scratch; /* Test public API */ scratch = secp256k1_scratch_space_create(CTX, 1000); @@ -455,16 +457,7 @@ static void run_scratch_tests(void) { CHECK_ERROR_VOID(CTX, secp256k1_scratch_apply_checkpoint(&CTX->error_callback, scratch, checkpoint_2)); /* checkpoint_2 is after checkpoint */ CHECK_ERROR_VOID(CTX, secp256k1_scratch_apply_checkpoint(&CTX->error_callback, scratch, (size_t) -1)); /* this is just wildly invalid */ - /* try to use badly initialized scratch space */ - secp256k1_scratch_space_destroy(CTX, scratch); - memset(&local_scratch, 0, sizeof(local_scratch)); - scratch = &local_scratch; - CHECK_ERROR(CTX, secp256k1_scratch_max_allocation(&CTX->error_callback, scratch, 0)); - CHECK_ERROR(CTX, secp256k1_scratch_alloc(&CTX->error_callback, scratch, 500)); - CHECK_ERROR_VOID(CTX, secp256k1_scratch_space_destroy(CTX, scratch)); - /* Test that large integers do not wrap around in a bad way */ - scratch = secp256k1_scratch_space_create(CTX, 1000); /* Try max allocation with a large number of objects. Only makes sense if * ALIGNMENT is greater than 1 because otherwise the objects take no extra * space. */ @@ -479,6 +472,21 @@ static void run_scratch_tests(void) { secp256k1_scratch_space_destroy(CTX, NULL); /* no-op */ } +/* try to use badly initialized scratch space */ +static void run_invalid_scratch_space_tests(void) { + secp256k1_scratch_space* scratch = checked_malloc(&CTX->error_callback, sizeof(*scratch)); + size_t magic_size = sizeof(scratch->magic); + memset(scratch, 0, sizeof(*scratch)); + /* catch accesses beyond the magic */ + SECP256K1_CHECKMEM_UNDEFINE((unsigned char*)scratch + magic_size, sizeof(*scratch) - magic_size); + + CHECK_ERROR(CTX, secp256k1_scratch_max_allocation(&CTX->error_callback, scratch, 0)); + CHECK_ERROR(CTX, secp256k1_scratch_alloc(&CTX->error_callback, scratch, 500)); + CHECK_ERROR_VOID(CTX, secp256k1_scratch_space_destroy(CTX, scratch)); + + free(scratch); +} + /* 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; @@ -3112,6 +3120,18 @@ static int fe_equal(const secp256k1_fe *a, const secp256k1_fe *b) { return secp256k1_fe_equal(&an, &bn); } +static void run_fe_equal_magnitude_boundaries(void) { + int i; + secp256k1_fe a, b; + for (i = 0; i < 100 * COUNT; ++i) { + testutil_random_fe(&a); + b = a; + testutil_random_fe_magnitude(&a, 1); + testutil_random_fe_magnitude(&b, 30); + CHECK(secp256k1_fe_equal(&a, &b)); + } +} + static void run_field_convert(void) { static const unsigned char b32[32] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, @@ -4360,19 +4380,16 @@ static void test_ec_combine(void) { const secp256k1_pubkey* d[6]; secp256k1_pubkey sd; secp256k1_pubkey sd2; - secp256k1_gej Qj; secp256k1_ge Q; int i; for (i = 1; i <= 6; i++) { secp256k1_scalar s; testutil_random_scalar_order_test(&s); secp256k1_scalar_add(&sum, &sum, &s); - secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &Qj, &s); - secp256k1_ge_set_gej(&Q, &Qj); + secp256k1_ecmult_gen_ge(&CTX->ecmult_gen_ctx, &Q, &s); secp256k1_pubkey_save(&data[i - 1], &Q); d[i - 1] = &data[i - 1]; - secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &Qj, &sum); - secp256k1_ge_set_gej(&Q, &Qj); + secp256k1_ecmult_gen_ge(&CTX->ecmult_gen_ctx, &Q, &sum); secp256k1_pubkey_save(&sd, &Q); CHECK(secp256k1_ec_pubkey_combine(CTX, &sd2, d, i) == 1); CHECK(secp256k1_memcmp_var(&sd, &sd2, sizeof(sd)) == 0); @@ -4397,8 +4414,7 @@ static void test_ec_commit(void) { /* Create random keypair and data */ testutil_random_scalar_order_test(&seckey_s); - secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &pubkeyj, &seckey_s); - secp256k1_ge_set_gej(&pubkey, &pubkeyj); + secp256k1_ecmult_gen_ge(&CTX->ecmult_gen_ctx, &pubkey, &seckey_s); testrand256_test(data); /* Commit to data and verify */ @@ -4408,7 +4424,7 @@ static void test_ec_commit(void) { CHECK(secp256k1_ec_commit_verify(hash_ctx, &commitment, &pubkey, &sha, data, 32) == 1); secp256k1_sha256_initialize(&sha); CHECK(secp256k1_ec_commit_seckey(hash_ctx, &seckey_s, &pubkey, &sha, data, 32) == 1); - secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &pubkeyj, &seckey_s); + secp256k1_ecmult_gen_gej(&CTX->ecmult_gen_ctx, &pubkeyj, &seckey_s); secp256k1_gej_eq_ge_var(&pubkeyj, &commitment); /* Check that verification fails with different data */ @@ -4430,7 +4446,6 @@ static void test_ec_commit_api(void) { unsigned char seckey[32]; secp256k1_scalar seckey_s; secp256k1_ge pubkey; - secp256k1_gej pubkeyj; secp256k1_ge commitment; unsigned char data[32]; secp256k1_sha256 sha; @@ -4440,8 +4455,7 @@ static void test_ec_commit_api(void) { /* Create random keypair */ testutil_random_scalar_order_test(&seckey_s); secp256k1_scalar_get_b32(seckey, &seckey_s); - secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &pubkeyj, &seckey_s); - secp256k1_ge_set_gej(&pubkey, &pubkeyj); + secp256k1_ecmult_gen_ge(&CTX->ecmult_gen_ctx, &pubkey, &seckey_s); secp256k1_sha256_initialize(&sha); CHECK(secp256k1_ec_commit(hash_ctx, &commitment, &pubkey, &sha, data, 1) == 1); @@ -4757,9 +4771,9 @@ static void test_ecmult_target(const secp256k1_scalar* target, int mode) { /* EC multiplications */ if (mode == 0) { - secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &p1j, &n1); - secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &p2j, &n2); - secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &ptj, target); + secp256k1_ecmult_gen_gej(&CTX->ecmult_gen_ctx, &p1j, &n1); + secp256k1_ecmult_gen_gej(&CTX->ecmult_gen_ctx, &p2j, &n2); + secp256k1_ecmult_gen_gej(&CTX->ecmult_gen_ctx, &ptj, target); } else if (mode == 1) { secp256k1_ecmult(&p1j, &pj, &n1, &secp256k1_scalar_zero); secp256k1_ecmult(&p2j, &pj, &n2, &secp256k1_scalar_zero); @@ -5326,7 +5340,7 @@ static int test_ecmult_multi_random(secp256k1_scratch *scratch) { secp256k1_scalar_mul(&scalars[filled], &sc_tmp, &g_scalar); secp256k1_scalar_inverse_var(&sc_tmp, &sc_tmp); secp256k1_scalar_negate(&sc_tmp, &sc_tmp); - secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &gejs[filled], &sc_tmp); + secp256k1_ecmult_gen_gej(&CTX->ecmult_gen_ctx, &gejs[filled], &sc_tmp); ++filled; ++mults; } @@ -5806,7 +5820,7 @@ static void test_ecmult_accumulate(secp256k1_sha256* acc, const secp256k1_scalar size_t i; secp256k1_gej_set_ge(&gj, &secp256k1_ge_const_g); secp256k1_gej_set_infinity(&infj); - secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &rj[0], x); + secp256k1_ecmult_gen_gej(&CTX->ecmult_gen_ctx, &rj[0], x); secp256k1_ecmult(&rj[1], &gj, x, NULL); secp256k1_ecmult(&rj[2], &gj, x, &secp256k1_scalar_zero); secp256k1_ecmult(&rj[3], &infj, &secp256k1_scalar_zero, x); @@ -5950,6 +5964,25 @@ static void run_ecmult_constants(void) { } } +static void run_ecmult_gen_ge(void) { + /* Test that secp256k1_ecmult_gen_ge result matches secp256k1_ecmult_gen_gej with + * manual Jacobian-to-affine conversion (secp256k1_ge_set_gej) over random scalars */ + int i; + + for (i = 0; i < COUNT; i++) { + secp256k1_scalar scalar; + secp256k1_gej result_gej; + secp256k1_ge result_ge, expected_ge; + + testutil_random_scalar_order_test(&scalar); + secp256k1_ecmult_gen_gej(&CTX->ecmult_gen_ctx, &result_gej, &scalar); + secp256k1_ge_set_gej(&expected_ge, &result_gej); + secp256k1_ecmult_gen_ge(&CTX->ecmult_gen_ctx, &result_ge, &scalar); + + CHECK(secp256k1_ge_eq_var(&result_ge, &expected_ge)); + } +} + static void test_ecmult_gen_blind(void) { /* Test ecmult_gen() blinding and confirm that the blinding changes, the affine points match, and the z's don't match. */ secp256k1_scalar key; @@ -5960,13 +5993,13 @@ static void test_ecmult_gen_blind(void) { secp256k1_ge p; secp256k1_ge pge; testutil_random_scalar_order_test(&key); - secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &pgej, &key); + secp256k1_ecmult_gen_gej(&CTX->ecmult_gen_ctx, &pgej, &key); testrand256(seed32); b = CTX->ecmult_gen_ctx.scalar_offset; p = CTX->ecmult_gen_ctx.ge_offset; 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); + secp256k1_ecmult_gen_gej(&CTX->ecmult_gen_ctx, &pgej2, &key); CHECK(!gej_xyz_equals_gej(&pgej, &pgej2)); CHECK(!secp256k1_ge_eq_var(&p, &CTX->ecmult_gen_ctx.ge_offset)); secp256k1_ge_set_gej(&pge, &pgej); @@ -5996,7 +6029,7 @@ static void test_ecmult_gen_edge_cases(void) { for (i = -1; i < 2; ++i) { /* Run test with gn = i - scalar_offset (so that the ecmult_gen recoded value represents i). */ - secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &res1, &gn); + secp256k1_ecmult_gen_gej(&CTX->ecmult_gen_ctx, &res1, &gn); secp256k1_ecmult(&res2, NULL, &secp256k1_scalar_zero, &gn); secp256k1_ecmult_const(&res3, &secp256k1_ge_const_g, &gn); CHECK(secp256k1_gej_eq_var(&res1, &res2)); @@ -6679,7 +6712,6 @@ static void random_sign(secp256k1_scalar *sigr, secp256k1_scalar *sigs, const se } static void test_ecdsa_sign_verify(void) { - secp256k1_gej pubj; secp256k1_ge pub; secp256k1_scalar one; secp256k1_scalar msg, key; @@ -6688,8 +6720,7 @@ static void test_ecdsa_sign_verify(void) { int recid; testutil_random_scalar_order_test(&msg); testutil_random_scalar_order_test(&key); - secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &pubj, &key); - secp256k1_ge_set_gej(&pub, &pubj); + secp256k1_ecmult_gen_ge(&CTX->ecmult_gen_ctx, &pub, &key); getrec = testrand_bits(1); /* The specific way in which this conditional is written sidesteps a potential bug in clang. See the commit messages of the commit that introduced this comment for details. */ @@ -7448,7 +7479,6 @@ static void run_ecdsa_edge_cases(void) { /* Test the case where ECDSA recomputes a point that is infinity. */ { - secp256k1_gej keyj; secp256k1_ge key; secp256k1_scalar msg; secp256k1_scalar sr, ss; @@ -7456,8 +7486,7 @@ static void run_ecdsa_edge_cases(void) { secp256k1_scalar_negate(&ss, &ss); secp256k1_scalar_inverse(&ss, &ss); secp256k1_scalar_set_int(&sr, 1); - secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &keyj, &sr); - secp256k1_ge_set_gej(&key, &keyj); + secp256k1_ecmult_gen_ge(&CTX->ecmult_gen_ctx, &key, &sr); msg = ss; CHECK(secp256k1_ecdsa_sig_verify(&sr, &ss, &key, &msg) == 0); } @@ -8116,6 +8145,7 @@ static const struct tf_test_entry tests_general[] = { CASE(all_static_context_tests), CASE(deprecated_context_flags_test), CASE(scratch_tests), + CASE(invalid_scratch_space_tests), CASE(plug_sha256_compression_tests), CASE(sha256_multi_block_compression_tests), }; @@ -8145,6 +8175,7 @@ static const struct tf_test_entry tests_scalar[] = { static const struct tf_test_entry tests_field[] = { CASE(field_half), CASE(field_misc), + CASE(fe_equal_magnitude_boundaries), CASE(field_convert), CASE(field_be32_overflow), CASE(fe_mul), @@ -8165,6 +8196,7 @@ static const struct tf_test_entry tests_ecmult[] = { CASE(ecmult_near_split_bound), CASE(ecmult_chain), CASE(ecmult_constants), + CASE(ecmult_gen_ge), CASE(ecmult_gen_blind), CASE(ecmult_const_tests), CASE(ecmult_multi_tests), @@ -8176,6 +8208,7 @@ static const struct tf_test_entry tests_ec[] = { CASE(ec_pubkey_parse_test), CASE(eckey_edge_case_test), CASE(eckey_negate_test), + CASE(ec_commit), }; static const struct tf_test_entry tests_ecdsa[] = { @@ -8197,6 +8230,7 @@ static const struct tf_test_entry tests_utils[] = { CASE(secp256k1_is_zero_array_test), CASE(secp256k1_byteorder_tests), CASE(cmov_tests), + CASE(util_tests), }; /* Register test modules */ @@ -8301,3 +8335,7 @@ int main(int argc, char **argv) { if (tf_init(&tf, argc, argv) != 0) return EXIT_FAILURE; return tf_run(&tf); } + +#if defined(__GNUC__) +# pragma GCC diagnostic pop +#endif diff --git a/src/secp256k1/src/tests_exhaustive.c b/src/secp256k1/src/tests_exhaustive.c index 68d4bec3f0..99d7b2448d 100644 --- a/src/secp256k1/src/tests_exhaustive.c +++ b/src/secp256k1/src/tests_exhaustive.c @@ -31,6 +31,11 @@ #include "testutil.h" #include "util.h" +#if defined(__GNUC__) +# pragma GCC diagnostic push +# pragma GCC diagnostic warning "-Wunused-function" +#endif + static int count = 2; static uint32_t num_cores = 1; @@ -337,6 +342,10 @@ static void test_exhaustive_sign(const secp256k1_context *ctx, const secp256k1_g */ } +#ifdef ENABLE_MODULE_ECDH +#include "modules/ecdh/tests_exhaustive_impl.h" +#endif + #ifdef ENABLE_MODULE_RECOVERY #include "modules/recovery/tests_exhaustive_impl.h" #endif @@ -417,12 +426,10 @@ int main(int argc, char** argv) { /* Verify against ecmult_gen */ { secp256k1_scalar scalar_i; - secp256k1_gej generatedj; secp256k1_ge generated; secp256k1_scalar_set_int(&scalar_i, i); - secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &generatedj, &scalar_i); - secp256k1_ge_set_gej(&generated, &generatedj); + secp256k1_ecmult_gen_ge(&ctx->ecmult_gen_ctx, &generated, &scalar_i); CHECK(!secp256k1_ge_is_infinity(&group[i])); CHECK(secp256k1_ge_eq_var(&group[i], &generated)); @@ -437,6 +444,9 @@ int main(int argc, char** argv) { test_exhaustive_sign(ctx, group); test_exhaustive_verify(ctx, group); +#ifdef ENABLE_MODULE_ECDH + test_exhaustive_ecdh(ctx, group); +#endif #ifdef ENABLE_MODULE_RECOVERY test_exhaustive_recovery(ctx, group); #endif @@ -462,3 +472,7 @@ int main(int argc, char** argv) { printf("no problems found\n"); return EXIT_SUCCESS; } + +#if defined(__GNUC__) +# pragma GCC diagnostic pop +#endif diff --git a/src/secp256k1/src/unit_test.c b/src/secp256k1/src/unit_test.c index a1858a117a..2ac709cc6c 100644 --- a/src/secp256k1/src/unit_test.c +++ b/src/secp256k1/src/unit_test.c @@ -17,6 +17,11 @@ #include "testrand.h" #include "tests_common.h" +#if defined(__GNUC__) +# pragma GCC diagnostic push +# pragma GCC diagnostic warning "-Wunused-function" +#endif + #define UNUSED(x) (void)(x) /* Number of times certain tests will run */ @@ -477,3 +482,7 @@ static int tf_run(struct tf_framework* tf) { return status; } + +#if defined(__GNUC__) +# pragma GCC diagnostic pop +#endif diff --git a/src/secp256k1/src/util.h b/src/secp256k1/src/util.h index 712e0fe9b4..2a35c40b87 100644 --- a/src/secp256k1/src/util.h +++ b/src/secp256k1/src/util.h @@ -57,6 +57,17 @@ static void print_buf_plain(const unsigned char *buf, size_t len) { # define SECP256K1_INLINE inline # endif +# if !defined(_DEBUG) && !defined(__NO_INLINE__) && !defined(__OPTIMIZE_SIZE__) +# if defined(__OPTIMIZE__) && (SECP256K1_GNUC_PREREQ(3, 0) || defined(__clang__)) +# define SECP256K1_FORCE_INLINE SECP256K1_INLINE __attribute__((always_inline)) +# elif defined(_MSC_VER) +# define SECP256K1_FORCE_INLINE __forceinline +# endif +# endif +# ifndef SECP256K1_FORCE_INLINE +# define SECP256K1_FORCE_INLINE SECP256K1_INLINE +# endif + /** Assert statically that expr is true. * * This is a statement-like macro and can only be used inside functions.