From 447334cb06de229024161021cc79b3af32ce8b5c Mon Sep 17 00:00:00 2001 From: Tim Ruffing Date: Sat, 24 Aug 2024 23:28:52 +0200 Subject: [PATCH 01/16] include: Avoid visibility("default") on Windows Fixes #1421. --- include/secp256k1.h | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/include/secp256k1.h b/include/secp256k1.h index cfbdd528c..41420ccf1 100644 --- a/include/secp256k1.h +++ b/include/secp256k1.h @@ -147,6 +147,15 @@ typedef int (*secp256k1_nonce_function)( * 1. If using Libtool, it defines DLL_EXPORT automatically. * 2. In other cases, SECP256K1_DLL_EXPORT must be defined. */ # define SECP256K1_API extern __declspec (dllexport) +# else + /* Building libsecp256k1 as a static library on Windows. + * No declspec is needed, and so we would want the non-Windows-specific + * logic below take care of this case. However, this may result in setting + * __attribute__ ((visibility("default"))), which is supposed to be a noop + * on Windows but may trigger warnings when compiling with -flto due to a + * bug in GCC, see + * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116478 . */ +# define SECP256K1_API extern # endif /* The user must define SECP256K1_STATIC when consuming libsecp256k1 as a static * library on Windows. */ @@ -156,11 +165,12 @@ typedef int (*secp256k1_nonce_function)( # endif #endif #ifndef SECP256K1_API +/* All cases not captured by the Windows-specific logic. */ # if defined(__GNUC__) && (__GNUC__ >= 4) && defined(SECP256K1_BUILD) - /* Building libsecp256k1 on non-Windows using GCC or compatible. */ + /* Building libsecp256k1 using GCC or compatible. */ # define SECP256K1_API extern __attribute__ ((visibility ("default"))) # else - /* All cases not captured above. */ + /* Fall back to standard C's extern. */ # define SECP256K1_API extern # endif #endif From 26e4a7c2146d581af47f02fc69e0728c7adb3bd8 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Wed, 26 Jun 2024 00:29:50 +0100 Subject: [PATCH 02/16] cmake: Set top-level target output locations This change: 1. Collects build artifacts in dedicated locations. 2. Allows to run individual examples with a shared library on Windows. 3. Is compatible with Wine when testing cross-compiled Windows binaries on Linux. 4. Is compatible with integration the project into a larger project hierarchy. --- .github/workflows/ci.yml | 8 ++++---- CMakeLists.txt | 9 +++++++++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0fc104d29..71bb3e9e5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -751,14 +751,14 @@ jobs: # Use the bash shell included with Git for Windows. shell: bash run: | - cd build/src/RelWithDebInfo && file *tests.exe bench*.exe libsecp256k1-*.dll || true + cd build/bin/RelWithDebInfo && file *tests.exe bench*.exe libsecp256k1-*.dll || true - name: Check run: | ctest -C RelWithDebInfo --test-dir build -j ([int]$env:NUMBER_OF_PROCESSORS + 1) - build\src\RelWithDebInfo\bench_ecmult.exe - build\src\RelWithDebInfo\bench_internal.exe - build\src\RelWithDebInfo\bench.exe + build\bin\RelWithDebInfo\bench_ecmult.exe + build\bin\RelWithDebInfo\bench_internal.exe + build\bin\RelWithDebInfo\bench.exe win64-native-headers: name: "x64 (MSVC): C++ (public headers)" diff --git a/CMakeLists.txt b/CMakeLists.txt index 3e2b779d9..0c4798f4b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -286,6 +286,15 @@ if(SECP256K1_APPEND_LDFLAGS) string(APPEND CMAKE_C_LINK_EXECUTABLE " ${SECP256K1_APPEND_LDFLAGS}") endif() +if(NOT CMAKE_RUNTIME_OUTPUT_DIRECTORY) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin) +endif() +if(NOT CMAKE_LIBRARY_OUTPUT_DIRECTORY) + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib) +endif() +if(NOT CMAKE_ARCHIVE_OUTPUT_DIRECTORY) + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib) +endif() add_subdirectory(src) if(SECP256K1_BUILD_EXAMPLES) add_subdirectory(examples) From c232486d84e21ece78b6cc956cd233cdf1bf8eee Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Wed, 26 Jun 2024 00:44:02 +0100 Subject: [PATCH 03/16] Revert "cmake: Set `ENVIRONMENT` property for examples on Windows" This reverts commit 116d2ab3df630455f23a7b21f50237689879ecc0. --- examples/CMakeLists.txt | 7 ------- 1 file changed, 7 deletions(-) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index fd1ebce39..a7a5adbf3 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -10,13 +10,6 @@ function(add_example name) ) set(test_name ${name}_example) add_test(NAME ${test_name} COMMAND ${target_name}) - if(BUILD_SHARED_LIBS AND MSVC) - # The DLL must reside either in the same folder where the executable is - # or somewhere in PATH. Using the latter option. - set_tests_properties(${test_name} PROPERTIES - ENVIRONMENT "PATH=$;$ENV{PATH}" - ) - endif() endfunction() add_example(ecdsa) From ef7ff03407fa79e7eab1b6771b77f72828e63636 Mon Sep 17 00:00:00 2001 From: Russell O'Connor Date: Wed, 25 Sep 2024 11:05:23 -0400 Subject: [PATCH 04/16] f can never equal -m In fact, before reaching this particular VERIFY_CHECK, we had already successfully passed through VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, -1) > 0); /* f > -modulus */ ensuring that f is not -m. --- src/modinv32_impl.h | 10 ++++------ src/modinv64_impl.h | 10 ++++------ 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/src/modinv32_impl.h b/src/modinv32_impl.h index 75eb354ff..981d2abc6 100644 --- a/src/modinv32_impl.h +++ b/src/modinv32_impl.h @@ -565,13 +565,12 @@ static void secp256k1_modinv32(secp256k1_modinv32_signed30 *x, const secp256k1_m /* g == 0 */ VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, 9, &SECP256K1_SIGNED30_ONE, 0) == 0); - /* |f| == 1, or (x == 0 and d == 0 and |f|=modulus) */ + /* |f| == 1, or (x == 0 and d == 0 and f == modulus) */ VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, 9, &SECP256K1_SIGNED30_ONE, -1) == 0 || secp256k1_modinv32_mul_cmp_30(&f, 9, &SECP256K1_SIGNED30_ONE, 1) == 0 || (secp256k1_modinv32_mul_cmp_30(x, 9, &SECP256K1_SIGNED30_ONE, 0) == 0 && secp256k1_modinv32_mul_cmp_30(&d, 9, &SECP256K1_SIGNED30_ONE, 0) == 0 && - (secp256k1_modinv32_mul_cmp_30(&f, 9, &modinfo->modulus, 1) == 0 || - secp256k1_modinv32_mul_cmp_30(&f, 9, &modinfo->modulus, -1) == 0))); + secp256k1_modinv32_mul_cmp_30(&f, 9, &modinfo->modulus, 1) == 0)); /* Optionally negate d, normalize to [0,modulus), and return it. */ secp256k1_modinv32_normalize_30(&d, f.v[8], modinfo); @@ -643,13 +642,12 @@ static void secp256k1_modinv32_var(secp256k1_modinv32_signed30 *x, const secp256 /* g == 0 */ VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &SECP256K1_SIGNED30_ONE, 0) == 0); - /* |f| == 1, or (x == 0 and d == 0 and |f|=modulus) */ + /* |f| == 1, or (x == 0 and d == 0 and f == modulus) */ VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &SECP256K1_SIGNED30_ONE, -1) == 0 || secp256k1_modinv32_mul_cmp_30(&f, len, &SECP256K1_SIGNED30_ONE, 1) == 0 || (secp256k1_modinv32_mul_cmp_30(x, 9, &SECP256K1_SIGNED30_ONE, 0) == 0 && secp256k1_modinv32_mul_cmp_30(&d, 9, &SECP256K1_SIGNED30_ONE, 0) == 0 && - (secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 1) == 0 || - secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, -1) == 0))); + secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 1) == 0)); /* Optionally negate d, normalize to [0,modulus), and return it. */ secp256k1_modinv32_normalize_30(&d, f.v[len - 1], modinfo); diff --git a/src/modinv64_impl.h b/src/modinv64_impl.h index 0dc1e8069..548787bed 100644 --- a/src/modinv64_impl.h +++ b/src/modinv64_impl.h @@ -621,13 +621,12 @@ static void secp256k1_modinv64(secp256k1_modinv64_signed62 *x, const secp256k1_m /* g == 0 */ VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, 5, &SECP256K1_SIGNED62_ONE, 0) == 0); - /* |f| == 1, or (x == 0 and d == 0 and |f|=modulus) */ + /* |f| == 1, or (x == 0 and d == 0 and f == modulus) */ VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, 5, &SECP256K1_SIGNED62_ONE, -1) == 0 || secp256k1_modinv64_mul_cmp_62(&f, 5, &SECP256K1_SIGNED62_ONE, 1) == 0 || (secp256k1_modinv64_mul_cmp_62(x, 5, &SECP256K1_SIGNED62_ONE, 0) == 0 && secp256k1_modinv64_mul_cmp_62(&d, 5, &SECP256K1_SIGNED62_ONE, 0) == 0 && - (secp256k1_modinv64_mul_cmp_62(&f, 5, &modinfo->modulus, 1) == 0 || - secp256k1_modinv64_mul_cmp_62(&f, 5, &modinfo->modulus, -1) == 0))); + secp256k1_modinv64_mul_cmp_62(&f, 5, &modinfo->modulus, 1) == 0)); /* Optionally negate d, normalize to [0,modulus), and return it. */ secp256k1_modinv64_normalize_62(&d, f.v[4], modinfo); @@ -698,13 +697,12 @@ static void secp256k1_modinv64_var(secp256k1_modinv64_signed62 *x, const secp256 /* g == 0 */ VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &SECP256K1_SIGNED62_ONE, 0) == 0); - /* |f| == 1, or (x == 0 and d == 0 and |f|=modulus) */ + /* |f| == 1, or (x == 0 and d == 0 and f == modulus) */ VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &SECP256K1_SIGNED62_ONE, -1) == 0 || secp256k1_modinv64_mul_cmp_62(&f, len, &SECP256K1_SIGNED62_ONE, 1) == 0 || (secp256k1_modinv64_mul_cmp_62(x, 5, &SECP256K1_SIGNED62_ONE, 0) == 0 && secp256k1_modinv64_mul_cmp_62(&d, 5, &SECP256K1_SIGNED62_ONE, 0) == 0 && - (secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 1) == 0 || - secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, -1) == 0))); + secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 1) == 0)); /* Optionally negate d, normalize to [0,modulus), and return it. */ secp256k1_modinv64_normalize_62(&d, f.v[len - 1], modinfo); From cd4f84f3ba8de37726274f61d5a34477c88433cf Mon Sep 17 00:00:00 2001 From: cheapshot003 Date: Thu, 29 Aug 2024 22:24:20 +0200 Subject: [PATCH 05/16] Improve examples/documentation: remove key generation loops Co-Authored by: Sebastian Falbesoner --- examples/ecdh.c | 22 ++++++++++------------ examples/ecdsa.c | 22 ++++++++++------------ examples/ellswift.c | 21 ++++++++++----------- examples/schnorr.c | 26 ++++++++++++-------------- include/secp256k1.h | 6 ++++-- 5 files changed, 46 insertions(+), 51 deletions(-) diff --git a/examples/ecdh.c b/examples/ecdh.c index d71fd2f60..ef9e8b896 100644 --- a/examples/ecdh.c +++ b/examples/ecdh.c @@ -42,18 +42,16 @@ int main(void) { assert(return_val); /*** Key Generation ***/ - - /* If the secret key is zero or out of range (bigger than secp256k1's - * order), we try to sample a new key. Note that the probability of this - * happening is negligible. */ - while (1) { - if (!fill_random(seckey1, sizeof(seckey1)) || !fill_random(seckey2, sizeof(seckey2))) { - printf("Failed to generate randomness\n"); - return 1; - } - if (secp256k1_ec_seckey_verify(ctx, seckey1) && secp256k1_ec_seckey_verify(ctx, seckey2)) { - break; - } + if (!fill_random(seckey1, sizeof(seckey1)) || !fill_random(seckey2, sizeof(seckey2))) { + printf("Failed to generate randomness\n"); + return 1; + } + /* If the secret key is zero or out of range (greater than secp256k1's + * order), we fail. Note that the probability of this occurring + * is negligible with a properly functioning random number generator. */ + if (!secp256k1_ec_seckey_verify(ctx, seckey1) || !secp256k1_ec_seckey_verify(ctx, seckey2)) { + printf("Generated secret key is invalid. This indicates an issue with the random number generator.\n"); + return 1; } /* Public key creation using a valid context with a verified secret key should never fail */ diff --git a/examples/ecdsa.c b/examples/ecdsa.c index d5c4613d9..433c58ffb 100644 --- a/examples/ecdsa.c +++ b/examples/ecdsa.c @@ -49,18 +49,16 @@ int main(void) { assert(return_val); /*** Key Generation ***/ - - /* If the secret key is zero or out of range (bigger than secp256k1's - * order), we try to sample a new key. Note that the probability of this - * happening is negligible. */ - while (1) { - if (!fill_random(seckey, sizeof(seckey))) { - printf("Failed to generate randomness\n"); - return 1; - } - if (secp256k1_ec_seckey_verify(ctx, seckey)) { - break; - } + /* If the secret key is zero or out of range (greater than secp256k1's + * order), we return 1. Note that the probability of this occurring + * is negligible with a properly functioning random number generator. */ + if (!fill_random(seckey, sizeof(seckey))) { + printf("Failed to generate randomness\n"); + return 1; + } + if (!secp256k1_ec_seckey_verify(ctx, seckey)) { + printf("Generated secret key is invalid. This indicates an issue with the random number generator.\n"); + return 1; } /* Public key creation using a valid context with a verified secret key should never fail */ diff --git a/examples/ellswift.c b/examples/ellswift.c index 52be7eebf..e6159f36c 100644 --- a/examples/ellswift.c +++ b/examples/ellswift.c @@ -48,17 +48,16 @@ int main(void) { /*** Generate secret keys ***/ - /* If the secret key is zero or out of range (bigger than secp256k1's - * order), we try to sample a new key. Note that the probability of this - * happening is negligible. */ - while (1) { - if (!fill_random(seckey1, sizeof(seckey1)) || !fill_random(seckey2, sizeof(seckey2))) { - printf("Failed to generate randomness\n"); - return 1; - } - if (secp256k1_ec_seckey_verify(ctx, seckey1) && secp256k1_ec_seckey_verify(ctx, seckey2)) { - break; - } + /* If the secret key is zero or out of range (greater than secp256k1's + * order), we return 1. Note that the probability of this occurring + * is negligible with a properly functioning random number generator. */ + if (!fill_random(seckey1, sizeof(seckey1)) || !fill_random(seckey2, sizeof(seckey2))) { + printf("Failed to generate randomness\n"); + return 1; + } + if (!secp256k1_ec_seckey_verify(ctx, seckey1) || !secp256k1_ec_seckey_verify(ctx, seckey2)) { + printf("Generated secret key is invalid. This indicates an issue with the random number generator.\n"); + return 1; } /* Generate ElligatorSwift public keys. This should never fail with valid context and diff --git a/examples/schnorr.c b/examples/schnorr.c index 8d5d14bda..adced235b 100644 --- a/examples/schnorr.c +++ b/examples/schnorr.c @@ -43,20 +43,18 @@ int main(void) { assert(return_val); /*** Key Generation ***/ - - /* If the secret key is zero or out of range (bigger than secp256k1's - * order), we try to sample a new key. Note that the probability of this - * happening is negligible. */ - while (1) { - if (!fill_random(seckey, sizeof(seckey))) { - printf("Failed to generate randomness\n"); - return 1; - } - /* Try to create a keypair with a valid context, it should only fail if - * the secret key is zero or out of range. */ - if (secp256k1_keypair_create(ctx, &keypair, seckey)) { - break; - } + /* If the secret key is zero or out of range (greater than secp256k1's + * order), we return 1. Note that the probability of this occurring + * is negligible with a properly functioning random number generator. */ + if (!fill_random(seckey, sizeof(seckey))) { + printf("Failed to generate randomness\n"); + return 1; + } + /* Try to create a keypair with a valid context, it should only fail if + * the secret key is zero or out of range. */ + if (!secp256k1_keypair_create(ctx, &keypair, seckey)) { + printf("Generated secret key is invalid. This indicates an issue with the random number generator.\n"); + return 1; } /* Extract the X-only public key from the keypair. We pass NULL for diff --git a/include/secp256k1.h b/include/secp256k1.h index cfbdd528c..88928111c 100644 --- a/include/secp256k1.h +++ b/include/secp256k1.h @@ -679,12 +679,14 @@ SECP256K1_API int secp256k1_ecdsa_sign( const void *ndata ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); -/** Verify an ECDSA secret key. +/** Verify an elliptic curve secret key. * * A secret key is valid if it is not 0 and less than the secp256k1 curve order * when interpreted as an integer (most significant byte first). The * probability of choosing a 32-byte string uniformly at random which is an - * invalid secret key is negligible. + * invalid secret key is negligible. However, if it does happen it should + * be assumed that the randomness source is severely broken and there should + * be no retry. * * Returns: 1: secret key is valid * 0: secret key is invalid From 70b6be1834e2ece8d9cfcf2ad12e4452c87cdc20 Mon Sep 17 00:00:00 2001 From: Jonas Nick Date: Sun, 13 Oct 2024 19:08:02 +0000 Subject: [PATCH 06/16] extrakeys: improve doc of keypair_create (don't suggest retry) --- include/secp256k1.h | 2 +- include/secp256k1_extrakeys.h | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/include/secp256k1.h b/include/secp256k1.h index 6e96778da..25196fb75 100644 --- a/include/secp256k1.h +++ b/include/secp256k1.h @@ -684,7 +684,7 @@ SECP256K1_API int secp256k1_ecdsa_sign( * A secret key is valid if it is not 0 and less than the secp256k1 curve order * when interpreted as an integer (most significant byte first). The * probability of choosing a 32-byte string uniformly at random which is an - * invalid secret key is negligible. However, if it does happen it should + * invalid secret key is negligible. However, if it does happen it should * be assumed that the randomness source is severely broken and there should * be no retry. * diff --git a/include/secp256k1_extrakeys.h b/include/secp256k1_extrakeys.h index ad70b92f9..13acb0325 100644 --- a/include/secp256k1_extrakeys.h +++ b/include/secp256k1_extrakeys.h @@ -155,10 +155,13 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_tweak_add_ const unsigned char *tweak32 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5); -/** Compute the keypair for a secret key. +/** Compute the keypair for a valid secret key. * - * Returns: 1: secret was valid, keypair is ready to use - * 0: secret was invalid, try again with a different secret + * See the documentation of `secp256k1_ec_seckey_verify` for more information + * about the validity of secret keys. + * + * Returns: 1: secret key is valid + * 0: secret key is invalid * Args: ctx: pointer to a context object (not secp256k1_context_static). * Out: keypair: pointer to the created keypair. * In: seckey: pointer to a 32-byte secret key. From e8908221a45a368c2c8ae0fed0e2310968d4815a Mon Sep 17 00:00:00 2001 From: Jonas Nick Date: Sun, 13 Oct 2024 19:10:45 +0000 Subject: [PATCH 07/16] examples: do not retry generating seckey randomness in musig --- examples/musig.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/examples/musig.c b/examples/musig.c index 396dbb9f1..0352dc40f 100644 --- a/examples/musig.c +++ b/examples/musig.c @@ -38,14 +38,17 @@ struct signer { /* Create a key pair, store it in signer_secrets->keypair and signer->pubkey */ static int create_keypair(const secp256k1_context* ctx, struct signer_secrets *signer_secrets, struct signer *signer) { unsigned char seckey[32]; - while (1) { - if (!fill_random(seckey, sizeof(seckey))) { - printf("Failed to generate randomness\n"); - return 0; - } - if (secp256k1_keypair_create(ctx, &signer_secrets->keypair, seckey)) { - break; - } + + if (!fill_random(seckey, sizeof(seckey))) { + printf("Failed to generate randomness\n"); + return 0; + } + /* Try to create a keypair with a valid context. This only fails if the + * secret key is zero or out of range (greater than secp256k1's order). Note + * that the probability of this occurring is negligible with a properly + * functioning random number generator. */ + if (!secp256k1_keypair_create(ctx, &signer_secrets->keypair, seckey)) { + return 0; } if (!secp256k1_keypair_pub(ctx, &signer->pubkey, &signer_secrets->keypair)) { return 0; From 5bab8f6d3c4946f32bebd2a99b9975aa160ff794 Mon Sep 17 00:00:00 2001 From: Jonas Nick Date: Sun, 13 Oct 2024 19:11:02 +0000 Subject: [PATCH 08/16] examples: make key generation doc consistent --- examples/ecdh.c | 4 ++-- examples/ecdsa.c | 6 +++--- examples/ellswift.c | 7 +++---- examples/schnorr.c | 11 +++++------ 4 files changed, 13 insertions(+), 15 deletions(-) diff --git a/examples/ecdh.c b/examples/ecdh.c index ef9e8b896..13aa760b2 100644 --- a/examples/ecdh.c +++ b/examples/ecdh.c @@ -47,8 +47,8 @@ int main(void) { return 1; } /* If the secret key is zero or out of range (greater than secp256k1's - * order), we fail. Note that the probability of this occurring - * is negligible with a properly functioning random number generator. */ + * order), we fail. Note that the probability of this occurring is negligible + * with a properly functioning random number generator. */ if (!secp256k1_ec_seckey_verify(ctx, seckey1) || !secp256k1_ec_seckey_verify(ctx, seckey2)) { printf("Generated secret key is invalid. This indicates an issue with the random number generator.\n"); return 1; diff --git a/examples/ecdsa.c b/examples/ecdsa.c index 433c58ffb..80ae9d46c 100644 --- a/examples/ecdsa.c +++ b/examples/ecdsa.c @@ -49,13 +49,13 @@ int main(void) { assert(return_val); /*** Key Generation ***/ - /* If the secret key is zero or out of range (greater than secp256k1's - * order), we return 1. Note that the probability of this occurring - * is negligible with a properly functioning random number generator. */ if (!fill_random(seckey, sizeof(seckey))) { printf("Failed to generate randomness\n"); return 1; } + /* If the secret key is zero or out of range (greater than secp256k1's + * order), we fail. Note that the probability of this occurring is negligible + * with a properly functioning random number generator. */ if (!secp256k1_ec_seckey_verify(ctx, seckey)) { printf("Generated secret key is invalid. This indicates an issue with the random number generator.\n"); return 1; diff --git a/examples/ellswift.c b/examples/ellswift.c index e6159f36c..afb2fee40 100644 --- a/examples/ellswift.c +++ b/examples/ellswift.c @@ -47,14 +47,13 @@ int main(void) { assert(return_val); /*** Generate secret keys ***/ - - /* If the secret key is zero or out of range (greater than secp256k1's - * order), we return 1. Note that the probability of this occurring - * is negligible with a properly functioning random number generator. */ if (!fill_random(seckey1, sizeof(seckey1)) || !fill_random(seckey2, sizeof(seckey2))) { printf("Failed to generate randomness\n"); return 1; } + /* If the secret key is zero or out of range (greater than secp256k1's + * order), we fail. Note that the probability of this occurring is negligible + * with a properly functioning random number generator. */ if (!secp256k1_ec_seckey_verify(ctx, seckey1) || !secp256k1_ec_seckey_verify(ctx, seckey2)) { printf("Generated secret key is invalid. This indicates an issue with the random number generator.\n"); return 1; diff --git a/examples/schnorr.c b/examples/schnorr.c index adced235b..909fcaa1f 100644 --- a/examples/schnorr.c +++ b/examples/schnorr.c @@ -43,18 +43,17 @@ int main(void) { assert(return_val); /*** Key Generation ***/ - /* If the secret key is zero or out of range (greater than secp256k1's - * order), we return 1. Note that the probability of this occurring - * is negligible with a properly functioning random number generator. */ if (!fill_random(seckey, sizeof(seckey))) { printf("Failed to generate randomness\n"); return 1; } - /* Try to create a keypair with a valid context, it should only fail if - * the secret key is zero or out of range. */ + /* Try to create a keypair with a valid context. This only fails if the + * secret key is zero or out of range (greater than secp256k1's order). Note + * that the probability of this occurring is negligible with a properly + * functioning random number generator. */ if (!secp256k1_keypair_create(ctx, &keypair, seckey)) { printf("Generated secret key is invalid. This indicates an issue with the random number generator.\n"); - return 1; + return 1; } /* Extract the X-only public key from the keypair. We pass NULL for From 87384f5c0f2bdf2b500858a18f5397e8dcffa8ec Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Mon, 12 Aug 2024 12:07:45 +0100 Subject: [PATCH 09/16] cmake, test: Add `secp256k1_` prefix to test names This change improves regex matching options when using `ctest` in downstream projects. --- examples/CMakeLists.txt | 2 +- src/CMakeLists.txt | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 675f4c8c3..c9da9de6b 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -9,7 +9,7 @@ function(add_example name) $<$:bcrypt> ) set(test_name ${name}_example) - add_test(NAME ${test_name} COMMAND ${target_name}) + add_test(NAME secp256k1_${test_name} COMMAND ${target_name}) endfunction() add_example(ecdsa) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index cc042b6ec..f31b8c8f5 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -87,12 +87,12 @@ endif() if(SECP256K1_BUILD_TESTS) add_executable(noverify_tests tests.c) target_link_libraries(noverify_tests secp256k1_precomputed secp256k1_asm) - add_test(NAME noverify_tests COMMAND noverify_tests) + add_test(NAME secp256k1_noverify_tests COMMAND noverify_tests) if(NOT CMAKE_BUILD_TYPE STREQUAL "Coverage") add_executable(tests tests.c) target_compile_definitions(tests PRIVATE VERIFY) target_link_libraries(tests secp256k1_precomputed secp256k1_asm) - add_test(NAME tests COMMAND tests) + add_test(NAME secp256k1_tests COMMAND tests) endif() endif() @@ -101,7 +101,7 @@ if(SECP256K1_BUILD_EXHAUSTIVE_TESTS) add_executable(exhaustive_tests tests_exhaustive.c) target_link_libraries(exhaustive_tests secp256k1_asm) target_compile_definitions(exhaustive_tests PRIVATE $<$>:VERIFY>) - add_test(NAME exhaustive_tests COMMAND exhaustive_tests) + add_test(NAME secp256k1_exhaustive_tests COMMAND exhaustive_tests) endif() if(SECP256K1_BUILD_CTIME_TESTS) From 57eda3ba300acb2e54f26a8ad00fbdd5750867ed Mon Sep 17 00:00:00 2001 From: Sebastian Falbesoner Date: Sun, 20 Oct 2024 02:25:06 +0200 Subject: [PATCH 10/16] musig: ctimetests: fix _declassify range for generated nonce points The area marked as non-secret exceeds the nonce_pts array in the second iteration of the for loop. Fix that by passing the correct size to the _declassify call. --- src/modules/musig/session_impl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/musig/session_impl.h b/src/modules/musig/session_impl.h index 2715b09d5..fbdfd6350 100644 --- a/src/modules/musig/session_impl.h +++ b/src/modules/musig/session_impl.h @@ -448,7 +448,7 @@ int secp256k1_musig_nonce_gen_internal(const secp256k1_context* ctx, secp256k1_m secp256k1_gej nonce_ptj; secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &nonce_ptj, &k[i]); secp256k1_ge_set_gej(&nonce_pts[i], &nonce_ptj); - secp256k1_declassify(ctx, &nonce_pts[i], sizeof(nonce_pts)); + secp256k1_declassify(ctx, &nonce_pts[i], sizeof(nonce_pts[i])); secp256k1_scalar_clear(&k[i]); } /* None of the nonce_pts will be infinity because k != 0 with overwhelming From 8be3839fb2e1e501ef82c5b341e5a7f88587997a Mon Sep 17 00:00:00 2001 From: Jonas Nick Date: Thu, 11 May 2023 13:24:37 +0000 Subject: [PATCH 11/16] Remove unused scratch space from API --- CHANGELOG.md | 3 +++ include/secp256k1.h | 36 ------------------------------------ src/scratch.h | 2 ++ src/secp256k1.c | 4 ++-- 4 files changed, 7 insertions(+), 38 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f2e0f538..5026aab1f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Document `doc/musig.md` for further notes on API usage. - Usage example `examples/musig.c`. +#### Removed + - Removed the `secp256k1_scratch_space` struct and its associated functions `secp256k1_scratch_space_create` `secp256k1_scratch_space_destroy` because the scratch space was unused in the API. + ## [0.5.1] - 2024-08-01 #### Added diff --git a/include/secp256k1.h b/include/secp256k1.h index 25196fb75..a28615a70 100644 --- a/include/secp256k1.h +++ b/include/secp256k1.h @@ -49,19 +49,6 @@ extern "C" { */ typedef struct secp256k1_context_struct secp256k1_context; -/** Opaque data structure that holds rewritable "scratch space" - * - * The purpose of this structure is to replace dynamic memory allocations, - * because we target architectures where this may not be available. It is - * essentially a resizable (within specified parameters) block of bytes, - * which is initially created either by memory allocation or TODO as a pointer - * into some fixed rewritable space. - * - * Unlike the context object, this cannot safely be shared between threads - * without additional synchronization logic. - */ -typedef struct secp256k1_scratch_space_struct secp256k1_scratch_space; - /** Opaque data structure that holds a parsed and valid public key. * * The exact representation of data inside is implementation defined and not @@ -392,29 +379,6 @@ SECP256K1_API void secp256k1_context_set_error_callback( const void *data ) SECP256K1_ARG_NONNULL(1); -/** Create a secp256k1 scratch space object. - * - * Returns: a newly created scratch space. - * Args: ctx: pointer to a context object. - * In: size: amount of memory to be available as scratch space. Some extra - * (<100 bytes) will be allocated for extra accounting. - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT secp256k1_scratch_space *secp256k1_scratch_space_create( - const secp256k1_context *ctx, - size_t size -) SECP256K1_ARG_NONNULL(1); - -/** Destroy a secp256k1 scratch space. - * - * The pointer may not be used afterwards. - * Args: ctx: pointer to a context object. - * scratch: space to destroy - */ -SECP256K1_API void secp256k1_scratch_space_destroy( - const secp256k1_context *ctx, - secp256k1_scratch_space *scratch -) 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/scratch.h b/src/scratch.h index 9dcb7581f..6164330b3 100644 --- a/src/scratch.h +++ b/src/scratch.h @@ -21,6 +21,8 @@ typedef struct secp256k1_scratch_space_struct { size_t max_size; } secp256k1_scratch; +typedef struct secp256k1_scratch_space_struct secp256k1_scratch_space; + static secp256k1_scratch* secp256k1_scratch_create(const secp256k1_callback* error_callback, size_t max_size); static void secp256k1_scratch_destroy(const secp256k1_callback* error_callback, secp256k1_scratch* scratch); diff --git a/src/secp256k1.c b/src/secp256k1.c index a8c249ad2..93b7b459a 100644 --- a/src/secp256k1.c +++ b/src/secp256k1.c @@ -220,12 +220,12 @@ void secp256k1_context_set_error_callback(secp256k1_context* ctx, void (*fun)(co ctx->error_callback.data = data; } -secp256k1_scratch_space* secp256k1_scratch_space_create(const secp256k1_context* ctx, size_t max_size) { +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); } -void secp256k1_scratch_space_destroy(const secp256k1_context *ctx, secp256k1_scratch_space* scratch) { +static void secp256k1_scratch_space_destroy(const secp256k1_context *ctx, secp256k1_scratch_space* scratch) { VERIFY_CHECK(ctx != NULL); secp256k1_scratch_destroy(&ctx->error_callback, scratch); } From 096e3e23f63df208b8fd2e4a1283bc06f615e92b Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Fri, 25 Oct 2024 08:18:02 +0100 Subject: [PATCH 12/16] ci: Update macOS image The macOS 12 GHA image has been deprecated since 2024-10-07. See: https://github.com/actions/runner-images/issues/10721 --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a0dd19b54..9550c7a16 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -612,9 +612,9 @@ jobs: if: ${{ always() }} x86_64-macos-native: - name: "x86_64: macOS Monterey, Valgrind" + name: "x86_64: macOS Ventura, Valgrind" # See: https://github.com/actions/runner-images#available-images. - runs-on: macos-12 + runs-on: macos-13 env: CC: 'clang' From 980c08df80aa1698bf7e8f1f4f8ecf20078535a8 Mon Sep 17 00:00:00 2001 From: Tim Ruffing Date: Fri, 25 Oct 2024 16:00:25 +0200 Subject: [PATCH 13/16] util: Remove unused (u)int64_t formatting macros We should anyway prefer to use the predefined macros from . If I haven't missed anything, this removes the last OS-specific #if, leaving us only with compiler-specific #if(def)s. --- src/util.h | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/util.h b/src/util.h index 49af867a4..ff9271ede 100644 --- a/src/util.h +++ b/src/util.h @@ -192,14 +192,6 @@ static SECP256K1_INLINE void *checked_malloc(const secp256k1_callback* cb, size_ # endif #endif -#if defined(_WIN32) -# define I64FORMAT "I64d" -# define I64uFORMAT "I64u" -#else -# define I64FORMAT "lld" -# define I64uFORMAT "llu" -#endif - #if defined(__GNUC__) # define SECP256K1_GNUC_EXT __extension__ #else From 0f73caf7c62564dd4a28cdf682ea9644d1be0ef4 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Wed, 30 Oct 2024 14:30:55 +0000 Subject: [PATCH 14/16] test, ci: Lower default iteration count to 16 The number of test iterations in the CI remains unchanged. Additionally, the minimum iteration counts to enable the `test_ecmult_constants_2bit` test is adjusted from 35 to 16, so it is run by default. --- .cirrus.yml | 2 +- .github/workflows/ci.yml | 2 +- src/tests.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index 0c1e01dc9..9a9ca8e71 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -24,7 +24,7 @@ env: SCHNORRSIG: no ELLSWIFT: no ### test options - SECP256K1_TEST_ITERS: + SECP256K1_TEST_ITERS: 64 BENCH: yes SECP256K1_BENCH_ITERS: 2 CTIMETESTS: yes diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0fc104d29..77815ceb5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -35,7 +35,7 @@ env: SCHNORRSIG: 'no' ELLSWIFT: 'no' ### test options - SECP256K1_TEST_ITERS: + SECP256K1_TEST_ITERS: 64 BENCH: 'yes' SECP256K1_BENCH_ITERS: 2 CTIMETESTS: 'yes' diff --git a/src/tests.c b/src/tests.c index 70c15f870..bde10161a 100644 --- a/src/tests.c +++ b/src/tests.c @@ -37,7 +37,7 @@ #define CONDITIONAL_TEST(cnt, nam) if (COUNT < (cnt)) { printf("Skipping %s (iteration count too low)\n", nam); } else -static int COUNT = 64; +static int COUNT = 16; static secp256k1_context *CTX = NULL; static secp256k1_context *STATIC_CTX = NULL; @@ -5515,7 +5515,7 @@ static void run_ecmult_constants(void) { test_ecmult_constants_sha(1607366309u, 2048, expected32_8bit8); } - CONDITIONAL_TEST(35, "test_ecmult_constants_2bit") { + CONDITIONAL_TEST(16, "test_ecmult_constants_2bit") { test_ecmult_constants_2bit(); } } From 694342fdb71722b31dd4b6bc7241b992fdf6f492 Mon Sep 17 00:00:00 2001 From: Ava Chow Date: Thu, 31 Oct 2024 13:55:52 -0400 Subject: [PATCH 15/16] Name public API structs --- include/secp256k1.h | 4 ++-- include/secp256k1_extrakeys.h | 4 ++-- include/secp256k1_musig.h | 12 ++++++------ include/secp256k1_recovery.h | 2 +- include/secp256k1_schnorrsig.h | 2 +- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/include/secp256k1.h b/include/secp256k1.h index b0c5e6340..c6e9417f0 100644 --- a/include/secp256k1.h +++ b/include/secp256k1.h @@ -58,7 +58,7 @@ typedef struct secp256k1_context_struct secp256k1_context; * use secp256k1_ec_pubkey_serialize and secp256k1_ec_pubkey_parse. To * compare keys, use secp256k1_ec_pubkey_cmp. */ -typedef struct { +typedef struct secp256k1_pubkey { unsigned char data[64]; } secp256k1_pubkey; @@ -71,7 +71,7 @@ typedef struct { * comparison, use the secp256k1_ecdsa_signature_serialize_* and * secp256k1_ecdsa_signature_parse_* functions. */ -typedef struct { +typedef struct secp256k1_ecdsa_signature { unsigned char data[64]; } secp256k1_ecdsa_signature; diff --git a/include/secp256k1_extrakeys.h b/include/secp256k1_extrakeys.h index 13acb0325..48c98693c 100644 --- a/include/secp256k1_extrakeys.h +++ b/include/secp256k1_extrakeys.h @@ -19,7 +19,7 @@ extern "C" { * use secp256k1_xonly_pubkey_serialize and secp256k1_xonly_pubkey_parse. To * compare keys, use secp256k1_xonly_pubkey_cmp. */ -typedef struct { +typedef struct secp256k1_xonly_pubkey { unsigned char data[64]; } secp256k1_xonly_pubkey; @@ -30,7 +30,7 @@ typedef struct { * guaranteed to be portable between different platforms or versions. It is * however guaranteed to be 96 bytes in size, and can be safely copied/moved. */ -typedef struct { +typedef struct secp256k1_keypair { unsigned char data[96]; } secp256k1_keypair; diff --git a/include/secp256k1_musig.h b/include/secp256k1_musig.h index 53501814e..11b8f08c8 100644 --- a/include/secp256k1_musig.h +++ b/include/secp256k1_musig.h @@ -40,7 +40,7 @@ extern "C" { * Guaranteed to be 197 bytes in size. No serialization and parsing functions * (yet). */ -typedef struct { +typedef struct secp256k1_musig_keyagg_cache { unsigned char data[197]; } secp256k1_musig_keyagg_cache; @@ -56,7 +56,7 @@ typedef struct { * Copying this data structure can result in nonce reuse which will leak the * secret signing key. */ -typedef struct { +typedef struct secp256k1_musig_secnonce { unsigned char data[132]; } secp256k1_musig_secnonce; @@ -65,7 +65,7 @@ typedef struct { * Guaranteed to be 132 bytes in size. Serialized and parsed with * `musig_pubnonce_serialize` and `musig_pubnonce_parse`. */ -typedef struct { +typedef struct secp256k1_musig_pubnonce { unsigned char data[132]; } secp256k1_musig_pubnonce; @@ -74,7 +74,7 @@ typedef struct { * Guaranteed to be 132 bytes in size. Serialized and parsed with * `musig_aggnonce_serialize` and `musig_aggnonce_parse`. */ -typedef struct { +typedef struct secp256k1_musig_aggnonce { unsigned char data[132]; } secp256k1_musig_aggnonce; @@ -84,7 +84,7 @@ typedef struct { * be secure. Guaranteed to be 133 bytes in size. No serialization and parsing * functions (yet). */ -typedef struct { +typedef struct secp256k1_musig_session { unsigned char data[133]; } secp256k1_musig_session; @@ -93,7 +93,7 @@ typedef struct { * Guaranteed to be 36 bytes in size. Serialized and parsed with * `musig_partial_sig_serialize` and `musig_partial_sig_parse`. */ -typedef struct { +typedef struct secp256k1_musig_partial_sig { unsigned char data[36]; } secp256k1_musig_partial_sig; diff --git a/include/secp256k1_recovery.h b/include/secp256k1_recovery.h index 78a3eee05..93a2e4ccb 100644 --- a/include/secp256k1_recovery.h +++ b/include/secp256k1_recovery.h @@ -21,7 +21,7 @@ extern "C" { * recoverability) will have identical representation, so they can be * memcmp'ed. */ -typedef struct { +typedef struct secp256k1_ecdsa_recoverable_signature { unsigned char data[65]; } secp256k1_ecdsa_recoverable_signature; diff --git a/include/secp256k1_schnorrsig.h b/include/secp256k1_schnorrsig.h index 23163de2f..013d4ee73 100644 --- a/include/secp256k1_schnorrsig.h +++ b/include/secp256k1_schnorrsig.h @@ -79,7 +79,7 @@ SECP256K1_API const secp256k1_nonce_function_hardened secp256k1_nonce_function_b * secp256k1_nonce_function_bip340 is used, then ndata must be a * pointer to 32-byte auxiliary randomness as per BIP-340. */ -typedef struct { +typedef struct secp256k1_schnorrsig_extraparams { unsigned char magic[4]; secp256k1_nonce_function_hardened noncefp; void *ndata; From a8e6a3cc347b80908227020ed315ab43b894942a Mon Sep 17 00:00:00 2001 From: mllwchrry Date: Mon, 16 Feb 2026 16:12:41 +0200 Subject: [PATCH 16/16] Port bitcoin-core/secp256k1#1628 to zkp public API --- include/secp256k1_ecdsa_s2c.h | 2 +- include/secp256k1_generator.h | 4 ++-- include/secp256k1_surjectionproof.h | 4 ++-- include/secp256k1_whitelist.h | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/secp256k1_ecdsa_s2c.h b/include/secp256k1_ecdsa_s2c.h index ea4219feb..c931457d6 100644 --- a/include/secp256k1_ecdsa_s2c.h +++ b/include/secp256k1_ecdsa_s2c.h @@ -25,7 +25,7 @@ extern "C" { * If you need to convert to a format suitable for storage, transmission, or * comparison, use secp256k1_ecdsa_s2c_opening_serialize and secp256k1_ecdsa_s2c_opening_parse. */ -typedef struct { +typedef struct secp256k1_ecdsa_s2c_opening { unsigned char data[64]; } secp256k1_ecdsa_s2c_opening; diff --git a/include/secp256k1_generator.h b/include/secp256k1_generator.h index 0a59c3636..7bf323147 100644 --- a/include/secp256k1_generator.h +++ b/include/secp256k1_generator.h @@ -17,7 +17,7 @@ extern "C" { * If you need to convert to a format suitable for storage, transmission, or * comparison, use secp256k1_generator_serialize and secp256k1_generator_parse. */ -typedef struct { +typedef struct secp256k1_generator { unsigned char data[64]; } secp256k1_generator; @@ -100,7 +100,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_generator_generate_blin * comparison, use secp256k1_pedersen_commitment_serialize and * secp256k1_pedersen_commitment_parse. */ -typedef struct { +typedef struct secp256k1_pedersen_commitment { unsigned char data[64]; } secp256k1_pedersen_commitment; diff --git a/include/secp256k1_surjectionproof.h b/include/secp256k1_surjectionproof.h index c9a4aaee8..95c58384e 100644 --- a/include/secp256k1_surjectionproof.h +++ b/include/secp256k1_surjectionproof.h @@ -39,7 +39,7 @@ extern "C" { * The representation is exposed to allow creation of these objects on the * stack; please *do not* use these internals directly. */ -typedef struct { +typedef struct secp256k1_surjectionproof { #ifdef VERIFY /** Mark whether this proof has gone through `secp256k1_surjectionproof_initialize` */ int initialized; @@ -100,7 +100,7 @@ SECP256K1_API int secp256k1_surjectionproof_serialize( * data the API user wants to use as an asset tag. Its contents have no * semantic meaning to libsecp whatsoever. */ -typedef struct { +typedef struct secp256k1_fixed_asset_tag { unsigned char data[32]; } secp256k1_fixed_asset_tag; diff --git a/include/secp256k1_whitelist.h b/include/secp256k1_whitelist.h index 9f9decce9..20d495d39 100644 --- a/include/secp256k1_whitelist.h +++ b/include/secp256k1_whitelist.h @@ -31,7 +31,7 @@ extern "C" { * stack; please *do not* use these internals directly. To learn the number * of keys for a signature, use `secp256k1_whitelist_signature_n_keys`. */ -typedef struct { +typedef struct secp256k1_whitelist_signature { size_t n_keys; /* e0, scalars */ unsigned char data[32 * (1 + SECP256K1_WHITELIST_MAX_N_KEYS)];