From d3082ddeadef755d24523b2d4ae6b792138e847b Mon Sep 17 00:00:00 2001 From: Tim Ruffing Date: Tue, 8 Oct 2024 13:42:32 +0200 Subject: [PATCH 01/24] group: Add constant-time secp256k1_ge_set_all_gej This is a dump mechanical translation of secp256k1_ge_set_all_gej_var that assumes that inputs are not infinity. --- src/group.h | 6 +++++- src/group_impl.h | 46 ++++++++++++++++++++++++++++++++++++++++++++++ src/tests.c | 15 ++++++++++++++- 3 files changed, 65 insertions(+), 2 deletions(-) diff --git a/src/group.h b/src/group.h index 992ff5c98..05ae0d203 100644 --- a/src/group.h +++ b/src/group.h @@ -80,7 +80,11 @@ static void secp256k1_ge_set_gej(secp256k1_ge *r, secp256k1_gej *a); /** Set a group element equal to another which is given in jacobian coordinates. */ static void secp256k1_ge_set_gej_var(secp256k1_ge *r, secp256k1_gej *a); -/** Set a batch of group elements equal to the inputs given in jacobian coordinates */ +/** Set group elements r[0:len] (affine) equal to group elements a[0:len] (jacobian). + * None of the group elements in a[0:len] may be infinity. Constant time. */ +static void secp256k1_ge_set_all_gej(secp256k1_ge *r, const secp256k1_gej *a, size_t len); + +/** Set group elements r[0:len] (affine) equal to group elements a[0:len] (jacobian). */ static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a, size_t len); /** Bring a batch of inputs to the same global z "denominator", based on ratios between diff --git a/src/group_impl.h b/src/group_impl.h index 2e096f414..2e612dfb0 100644 --- a/src/group_impl.h +++ b/src/group_impl.h @@ -195,6 +195,52 @@ static void secp256k1_ge_set_gej_var(secp256k1_ge *r, secp256k1_gej *a) { SECP256K1_GE_VERIFY(r); } +static void secp256k1_ge_set_all_gej(secp256k1_ge *r, const secp256k1_gej *a, size_t len) { + secp256k1_fe u; + size_t i; + size_t last_i = SIZE_MAX; +#ifdef VERIFY + for (i = 0; i < len; i++) { + SECP256K1_GEJ_VERIFY(&a[i]); + VERIFY_CHECK(!secp256k1_gej_is_infinity(&a[i])); + } +#endif + + for (i = 0; i < len; i++) { + /* Use destination's x coordinates as scratch space */ + if (last_i == SIZE_MAX) { + r[i].x = a[i].z; + } else { + secp256k1_fe_mul(&r[i].x, &r[last_i].x, &a[i].z); + } + last_i = i; + } + if (last_i == SIZE_MAX) { + return; + } + secp256k1_fe_inv(&u, &r[last_i].x); + + i = last_i; + while (i > 0) { + i--; + secp256k1_fe_mul(&r[last_i].x, &r[i].x, &u); + secp256k1_fe_mul(&u, &u, &a[last_i].z); + last_i = i; + } + VERIFY_CHECK(!a[last_i].infinity); + r[last_i].x = u; + + for (i = 0; i < len; i++) { + secp256k1_ge_set_gej_zinv(&r[i], &a[i], &r[i].x); + } + +#ifdef VERIFY + for (i = 0; i < len; i++) { + SECP256K1_GE_VERIFY(&r[i]); + } +#endif +} + static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a, size_t len) { secp256k1_fe u; size_t i; diff --git a/src/tests.c b/src/tests.c index dba4097b1..61e758150 100644 --- a/src/tests.c +++ b/src/tests.c @@ -3822,14 +3822,27 @@ static void test_ge(void) { /* Test batch gej -> ge conversion without known z ratios. */ { + secp256k1_ge *ge_set_all_var = (secp256k1_ge *)checked_malloc(&CTX->error_callback, (4 * runs + 1) * sizeof(secp256k1_ge)); secp256k1_ge *ge_set_all = (secp256k1_ge *)checked_malloc(&CTX->error_callback, (4 * runs + 1) * sizeof(secp256k1_ge)); - secp256k1_ge_set_all_gej_var(ge_set_all, gej, 4 * runs + 1); + secp256k1_ge_set_all_gej_var(&ge_set_all_var[0], &gej[0], 4 * runs + 1); for (i = 0; i < 4 * runs + 1; i++) { + secp256k1_fe s; + testutil_random_fe_non_zero(&s); + secp256k1_gej_rescale(&gej[i], &s); + CHECK(secp256k1_gej_eq_ge_var(&gej[i], &ge_set_all_var[i])); + } + + /* Skip infinity at &gej[0]. */ + secp256k1_ge_set_all_gej(&ge_set_all[1], &gej[1], 4 * runs); + for (i = 1; i < 4 * runs + 1; i++) { secp256k1_fe s; testutil_random_fe_non_zero(&s); secp256k1_gej_rescale(&gej[i], &s); CHECK(secp256k1_gej_eq_ge_var(&gej[i], &ge_set_all[i])); + CHECK(secp256k1_ge_eq_var(&ge_set_all_var[i], &ge_set_all[i])); } + + free(ge_set_all_var); free(ge_set_all); } From 365f274ce3a18a876765e2a360685f6c35c347c2 Mon Sep 17 00:00:00 2001 From: Tim Ruffing Date: Tue, 8 Oct 2024 13:54:41 +0200 Subject: [PATCH 02/24] group: Simplify secp256k1_ge_set_all_gej No semantic changes. --- src/group_impl.h | 32 ++++++++++++-------------------- 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/src/group_impl.h b/src/group_impl.h index 2e612dfb0..7035cafb5 100644 --- a/src/group_impl.h +++ b/src/group_impl.h @@ -198,7 +198,6 @@ static void secp256k1_ge_set_gej_var(secp256k1_ge *r, secp256k1_gej *a) { static void secp256k1_ge_set_all_gej(secp256k1_ge *r, const secp256k1_gej *a, size_t len) { secp256k1_fe u; size_t i; - size_t last_i = SIZE_MAX; #ifdef VERIFY for (i = 0; i < len; i++) { SECP256K1_GEJ_VERIFY(&a[i]); @@ -206,29 +205,22 @@ static void secp256k1_ge_set_all_gej(secp256k1_ge *r, const secp256k1_gej *a, si } #endif - for (i = 0; i < len; i++) { - /* Use destination's x coordinates as scratch space */ - if (last_i == SIZE_MAX) { - r[i].x = a[i].z; - } else { - secp256k1_fe_mul(&r[i].x, &r[last_i].x, &a[i].z); - } - last_i = i; - } - if (last_i == SIZE_MAX) { + if (len == 0) { return; } - secp256k1_fe_inv(&u, &r[last_i].x); - i = last_i; - while (i > 0) { - i--; - secp256k1_fe_mul(&r[last_i].x, &r[i].x, &u); - secp256k1_fe_mul(&u, &u, &a[last_i].z); - last_i = i; + /* Use destination's x coordinates as scratch space */ + r[0].x = a[0].z; + for (i = 1; i < len; i++) { + secp256k1_fe_mul(&r[i].x, &r[i - 1].x, &a[i].z); } - VERIFY_CHECK(!a[last_i].infinity); - r[last_i].x = u; + secp256k1_fe_inv(&u, &r[len - 1].x); + + for (i = len - 1; i > 0; i--) { + secp256k1_fe_mul(&r[i].x, &r[i - 1].x, &u); + secp256k1_fe_mul(&u, &u, &a[i].z); + } + r[0].x = u; for (i = 0; i < len; i++) { secp256k1_ge_set_gej_zinv(&r[i], &a[i], &r[i].x); From 300aab1c056a05b2b4e289c0b9ac7a07c38cde5d Mon Sep 17 00:00:00 2001 From: Tim Ruffing Date: Tue, 8 Oct 2024 13:57:27 +0200 Subject: [PATCH 03/24] tests: Improve _ge_set_all_gej(_var) tests --- src/tests.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/tests.c b/src/tests.c index 61e758150..2d2c8e6eb 100644 --- a/src/tests.c +++ b/src/tests.c @@ -3842,6 +3842,17 @@ static void test_ge(void) { CHECK(secp256k1_ge_eq_var(&ge_set_all_var[i], &ge_set_all[i])); } + /* Test with an array of length 1. */ + secp256k1_ge_set_all_gej_var(ge_set_all_var, &gej[1], 1); + secp256k1_ge_set_all_gej(ge_set_all, &gej[1], 1); + CHECK(secp256k1_gej_eq_ge_var(&gej[1], &ge_set_all_var[1])); + CHECK(secp256k1_gej_eq_ge_var(&gej[1], &ge_set_all[1])); + CHECK(secp256k1_ge_eq_var(&ge_set_all_var[1], &ge_set_all[1])); + + /* Test with an array of length 0. */ + secp256k1_ge_set_all_gej_var(NULL, NULL, 0); + secp256k1_ge_set_all_gej(NULL, NULL, 0); + free(ge_set_all_var); free(ge_set_all); } From 64228a648fa137723e73c6e019378f58add18a1a Mon Sep 17 00:00:00 2001 From: Tim Ruffing Date: Tue, 8 Oct 2024 13:59:05 +0200 Subject: [PATCH 04/24] musig: Use _ge_set_all_gej for own public nonces --- src/modules/musig/session_impl.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/modules/musig/session_impl.h b/src/modules/musig/session_impl.h index fbdfd6350..b5d7c2217 100644 --- a/src/modules/musig/session_impl.h +++ b/src/modules/musig/session_impl.h @@ -395,6 +395,7 @@ static void secp256k1_nonce_function_musig(secp256k1_scalar *k, const unsigned c int secp256k1_musig_nonce_gen_internal(const secp256k1_context* ctx, secp256k1_musig_secnonce *secnonce, secp256k1_musig_pubnonce *pubnonce, const unsigned char *input_nonce, const unsigned char *seckey, const secp256k1_pubkey *pubkey, const unsigned char *msg32, const secp256k1_musig_keyagg_cache *keyagg_cache, const unsigned char *extra_input32) { secp256k1_scalar k[2]; secp256k1_ge nonce_pts[2]; + secp256k1_gej nonce_ptj[2]; int i; unsigned char pk_ser[33]; size_t pk_ser_len = sizeof(pk_ser); @@ -445,12 +446,13 @@ int secp256k1_musig_nonce_gen_internal(const secp256k1_context* ctx, secp256k1_m secp256k1_musig_secnonce_invalidate(ctx, secnonce, !ret); for (i = 0; i < 2; i++) { - 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[i])); + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &nonce_ptj[i], &k[i]); secp256k1_scalar_clear(&k[i]); } + secp256k1_ge_set_all_gej(nonce_pts, nonce_ptj, 2); + for (i = 0; i < 2; i++) { + secp256k1_declassify(ctx, &nonce_pts[i], sizeof(nonce_pts[i])); + } /* None of the nonce_pts will be infinity because k != 0 with overwhelming * probability */ secp256k1_musig_pubnonce_save(pubnonce, nonce_pts); From 1823594761046ae38e002781d65e9538dd211d27 Mon Sep 17 00:00:00 2001 From: Sebastian Falbesoner Date: Mon, 2 Dec 2024 18:20:18 +0100 Subject: [PATCH 05/24] Verify `compressed` argument in `secp256k1_eckey_pubkey_serialize` Due to similarity to the public API function `secp256k1_ec_pubkey_serialize`, public API flags like `SECP256K1_EC_COMPRESSED` are sometimes mistakingly passed to newly proposed code (this is currently the case for several modules in secp256k1-zkp, see https://github.com/BlockstreamResearch/secp256k1-zkp/pull/300). which is currently not detected. To avoid this in the future, a VERIFY_CHECK is added to check that the `compressed` argument is either 0 or 1. --- src/eckey_impl.h | 3 +++ src/secp256k1.c | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/eckey_impl.h b/src/eckey_impl.h index 121966f8b..a88a5964d 100644 --- a/src/eckey_impl.h +++ b/src/eckey_impl.h @@ -9,6 +9,7 @@ #include "eckey.h" +#include "util.h" #include "scalar.h" #include "field.h" #include "group.h" @@ -35,6 +36,8 @@ static int secp256k1_eckey_pubkey_parse(secp256k1_ge *elem, const unsigned char } static int secp256k1_eckey_pubkey_serialize(secp256k1_ge *elem, unsigned char *pub, size_t *size, int compressed) { + VERIFY_CHECK(compressed == 0 || compressed == 1); + if (secp256k1_ge_is_infinity(elem)) { return 0; } diff --git a/src/secp256k1.c b/src/secp256k1.c index a248519df..8b6f99375 100644 --- a/src/secp256k1.c +++ b/src/secp256k1.c @@ -280,7 +280,7 @@ int secp256k1_ec_pubkey_serialize(const secp256k1_context* ctx, unsigned char *o ARG_CHECK(pubkey != NULL); ARG_CHECK((flags & SECP256K1_FLAGS_TYPE_MASK) == SECP256K1_FLAGS_TYPE_COMPRESSION); if (secp256k1_pubkey_load(ctx, &Q, pubkey)) { - ret = secp256k1_eckey_pubkey_serialize(&Q, output, &len, flags & SECP256K1_FLAGS_BIT_COMPRESSION); + ret = secp256k1_eckey_pubkey_serialize(&Q, output, &len, !!(flags & SECP256K1_FLAGS_BIT_COMPRESSION)); if (ret) { *outputlen = len; } From 84c0bd1f7276c163cf0e34a5dfe6e307cd2bbd4a Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Fri, 13 Dec 2024 09:19:40 +0000 Subject: [PATCH 06/24] cmake: Adjust diagnostic flags for clang-cl --- CMakeLists.txt | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index aba6e5125..520a96efd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -242,17 +242,21 @@ endif() include(TryAppendCFlags) if(MSVC) - # Keep the following commands ordered lexicographically. + # For both cl and clang-cl compilers. try_append_c_flags(/W3) # Production quality warning level. + # Eliminate deprecation warnings for the older, less secure functions. + add_compile_definitions(_CRT_SECURE_NO_WARNINGS) +else() + try_append_c_flags(-Wall) # GCC >= 2.95 and probably many other compilers. +endif() +if(CMAKE_C_COMPILER_ID STREQUAL "MSVC") + # Keep the following commands ordered lexicographically. try_append_c_flags(/wd4146) # Disable warning C4146 "unary minus operator applied to unsigned type, result still unsigned". try_append_c_flags(/wd4244) # Disable warning C4244 "'conversion' conversion from 'type1' to 'type2', possible loss of data". try_append_c_flags(/wd4267) # Disable warning C4267 "'var' : conversion from 'size_t' to 'type', possible loss of data". - # Eliminate deprecation warnings for the older, less secure functions. - add_compile_definitions(_CRT_SECURE_NO_WARNINGS) else() # Keep the following commands ordered lexicographically. try_append_c_flags(-pedantic) - try_append_c_flags(-Wall) # GCC >= 2.95 and probably many other compilers. try_append_c_flags(-Wcast-align) # GCC >= 2.95. try_append_c_flags(-Wcast-align=strict) # GCC >= 8.0. try_append_c_flags(-Wconditional-uninitialized) # Clang >= 3.0 only. From 4c50d73dd98edc0b968525a291cf14b708bbdbf1 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Fri, 13 Dec 2024 09:35:55 +0000 Subject: [PATCH 07/24] ci: Add new "Windows (clang-cl)" job --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 54b2fab1c..c87de301c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -746,6 +746,8 @@ jobs: cpp_flags: '/DSECP256K1_MSVC_MULH_TEST_OVERRIDE' - job_name: 'x86 (MSVC): Windows (VS 2022)' cmake_options: '-A Win32' + - job_name: 'x64 (MSVC): Windows (clang-cl)' + cmake_options: '-T ClangCL' steps: - name: Checkout From 432ac57705b8e2f6a5874095214c443f1f8ea9bf Mon Sep 17 00:00:00 2001 From: Daniel Pfeifer Date: Fri, 22 Nov 2024 22:28:30 +0100 Subject: [PATCH 08/24] Make static context const --- include/secp256k1.h | 4 ++-- src/secp256k1.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/secp256k1.h b/include/secp256k1.h index c6e9417f0..ccb7457e3 100644 --- a/include/secp256k1.h +++ b/include/secp256k1.h @@ -230,10 +230,10 @@ typedef int (*secp256k1_nonce_function)( * * It is highly recommended to call secp256k1_selftest before using this context. */ -SECP256K1_API const secp256k1_context *secp256k1_context_static; +SECP256K1_API const secp256k1_context * const secp256k1_context_static; /** Deprecated alias for secp256k1_context_static. */ -SECP256K1_API const secp256k1_context *secp256k1_context_no_precomp +SECP256K1_API const secp256k1_context * const secp256k1_context_no_precomp SECP256K1_DEPRECATED("Use secp256k1_context_static instead"); /** Perform basic self tests (to be used in conjunction with secp256k1_context_static) diff --git a/src/secp256k1.c b/src/secp256k1.c index 8b6f99375..f047ca9e3 100644 --- a/src/secp256k1.c +++ b/src/secp256k1.c @@ -71,8 +71,8 @@ static const secp256k1_context secp256k1_context_static_ = { { secp256k1_default_error_callback_fn, 0 }, 0 }; -const secp256k1_context *secp256k1_context_static = &secp256k1_context_static_; -const secp256k1_context *secp256k1_context_no_precomp = &secp256k1_context_static_; +const secp256k1_context * const secp256k1_context_static = &secp256k1_context_static_; +const secp256k1_context * const secp256k1_context_no_precomp = &secp256k1_context_static_; /* Helper function that determines if a context is proper, i.e., is not the static context or a copy thereof. * From 37d2c60beca394e8f4733c65f5d558eb302cac06 Mon Sep 17 00:00:00 2001 From: Sebastian Falbesoner Date: Wed, 21 Aug 2024 00:57:38 +0200 Subject: [PATCH 09/24] Remove deprecated _ec_privkey_{negate,tweak_add,tweak_mul} aliases These function aliases have been described as DEPRECATED in the public API docs already many years ago (see #701, commit 41fc7856), and in addition explicit deprecation warnings are shown by the compiler at least since the first official release 0.2.0 (see PR #1089, commit fc94a2da), so it should be fine to just remove them by now. Co-authored-by: Tim Ruffing --- CHANGELOG.md | 5 +++++ include/secp256k1.h | 26 -------------------------- src/secp256k1.c | 12 ------------ src/tests.c | 19 ------------------- 4 files changed, 5 insertions(+), 57 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 05222e5ed..704217113 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +#### Removed +- Removed previously deprecated function aliases `secp256k1_ec_privkey_negate`, `secp256k1_ec_privkey_tweak_add` and + `secp256k1_ec_privkey_tweak_mul`. Use `secp256k1_ec_seckey_negate`, `secp256k1_ec_seckey_tweak_add` and + `secp256k1_ec_seckey_tweak_mul` instead. + ## [0.6.0] - 2024-11-04 #### Added diff --git a/include/secp256k1.h b/include/secp256k1.h index c6e9417f0..b7a099c70 100644 --- a/include/secp256k1.h +++ b/include/secp256k1.h @@ -701,14 +701,6 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_negate( unsigned char *seckey ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); -/** Same as secp256k1_ec_seckey_negate, but DEPRECATED. Will be removed in - * future versions. */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_negate( - const secp256k1_context *ctx, - unsigned char *seckey -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) - SECP256K1_DEPRECATED("Use secp256k1_ec_seckey_negate instead"); - /** Negates a public key in place. * * Returns: 1 always @@ -741,15 +733,6 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_tweak_add( const unsigned char *tweak32 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); -/** Same as secp256k1_ec_seckey_tweak_add, but DEPRECATED. Will be removed in - * future versions. */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_add( - const secp256k1_context *ctx, - unsigned char *seckey, - const unsigned char *tweak32 -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) - SECP256K1_DEPRECATED("Use secp256k1_ec_seckey_tweak_add instead"); - /** Tweak a public key by adding tweak times the generator to it. * * Returns: 0 if the arguments are invalid or the resulting public key would be @@ -788,15 +771,6 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_tweak_mul( const unsigned char *tweak32 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); -/** Same as secp256k1_ec_seckey_tweak_mul, but DEPRECATED. Will be removed in - * future versions. */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_mul( - const secp256k1_context *ctx, - unsigned char *seckey, - const unsigned char *tweak32 -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) - SECP256K1_DEPRECATED("Use secp256k1_ec_seckey_tweak_mul instead"); - /** Tweak a public key by multiplying it by a tweak value. * * Returns: 0 if the arguments are invalid. 1 otherwise. diff --git a/src/secp256k1.c b/src/secp256k1.c index 8b6f99375..b89ef36db 100644 --- a/src/secp256k1.c +++ b/src/secp256k1.c @@ -634,10 +634,6 @@ int secp256k1_ec_seckey_negate(const secp256k1_context* ctx, unsigned char *seck return ret; } -int secp256k1_ec_privkey_negate(const secp256k1_context* ctx, unsigned char *seckey) { - return secp256k1_ec_seckey_negate(ctx, seckey); -} - int secp256k1_ec_pubkey_negate(const secp256k1_context* ctx, secp256k1_pubkey *pubkey) { int ret = 0; secp256k1_ge p; @@ -681,10 +677,6 @@ int secp256k1_ec_seckey_tweak_add(const secp256k1_context* ctx, unsigned char *s return ret; } -int secp256k1_ec_privkey_tweak_add(const secp256k1_context* ctx, unsigned char *seckey, const unsigned char *tweak32) { - return secp256k1_ec_seckey_tweak_add(ctx, seckey, tweak32); -} - static int secp256k1_ec_pubkey_tweak_add_helper(secp256k1_ge *p, const unsigned char *tweak32) { secp256k1_scalar term; int overflow = 0; @@ -729,10 +721,6 @@ int secp256k1_ec_seckey_tweak_mul(const secp256k1_context* ctx, unsigned char *s return ret; } -int secp256k1_ec_privkey_tweak_mul(const secp256k1_context* ctx, unsigned char *seckey, const unsigned char *tweak32) { - return secp256k1_ec_seckey_tweak_mul(ctx, seckey, tweak32); -} - int secp256k1_ec_pubkey_tweak_mul(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const unsigned char *tweak32) { secp256k1_ge p; secp256k1_scalar factor; diff --git a/src/tests.c b/src/tests.c index 88628a14e..765835638 100644 --- a/src/tests.c +++ b/src/tests.c @@ -6248,11 +6248,6 @@ static void run_eckey_negate_test(void) { CHECK(secp256k1_ec_seckey_negate(CTX, seckey) == 1); CHECK(secp256k1_memcmp_var(seckey, seckey_tmp, 32) == 0); - /* Check that privkey alias gives same result */ - CHECK(secp256k1_ec_seckey_negate(CTX, seckey) == 1); - CHECK(secp256k1_ec_privkey_negate(CTX, seckey_tmp) == 1); - CHECK(secp256k1_memcmp_var(seckey, seckey_tmp, 32) == 0); - /* Negating all 0s fails */ memset(seckey, 0, 32); memset(seckey_tmp, 0, 32); @@ -6413,22 +6408,15 @@ static void test_ecdsa_end_to_end(void) { if (testrand_int(3) == 0) { int ret1; int ret2; - int ret3; unsigned char rnd[32]; - unsigned char privkey_tmp[32]; secp256k1_pubkey pubkey2; testrand256_test(rnd); - memcpy(privkey_tmp, privkey, 32); ret1 = secp256k1_ec_seckey_tweak_add(CTX, privkey, rnd); ret2 = secp256k1_ec_pubkey_tweak_add(CTX, &pubkey, rnd); - /* Check that privkey alias gives same result */ - ret3 = secp256k1_ec_privkey_tweak_add(CTX, privkey_tmp, rnd); CHECK(ret1 == ret2); - CHECK(ret2 == ret3); if (ret1 == 0) { return; } - CHECK(secp256k1_memcmp_var(privkey, privkey_tmp, 32) == 0); CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey2, privkey) == 1); CHECK(secp256k1_memcmp_var(&pubkey, &pubkey2, sizeof(pubkey)) == 0); } @@ -6437,22 +6425,15 @@ static void test_ecdsa_end_to_end(void) { if (testrand_int(3) == 0) { int ret1; int ret2; - int ret3; unsigned char rnd[32]; - unsigned char privkey_tmp[32]; secp256k1_pubkey pubkey2; testrand256_test(rnd); - memcpy(privkey_tmp, privkey, 32); ret1 = secp256k1_ec_seckey_tweak_mul(CTX, privkey, rnd); ret2 = secp256k1_ec_pubkey_tweak_mul(CTX, &pubkey, rnd); - /* Check that privkey alias gives same result */ - ret3 = secp256k1_ec_privkey_tweak_mul(CTX, privkey_tmp, rnd); CHECK(ret1 == ret2); - CHECK(ret2 == ret3); if (ret1 == 0) { return; } - CHECK(secp256k1_memcmp_var(privkey, privkey_tmp, 32) == 0); CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey2, privkey) == 1); CHECK(secp256k1_memcmp_var(&pubkey, &pubkey2, sizeof(pubkey)) == 0); } From 961ec25a8392415f3e1d3e88a43e81c12d716e72 Mon Sep 17 00:00:00 2001 From: Tim Ruffing Date: Mon, 10 Mar 2025 15:10:29 +0100 Subject: [PATCH 10/24] musig: Fix clearing of pubnonces Fixes a silent merge conflict between #1614 and #1579. --- src/modules/musig/session_impl.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/modules/musig/session_impl.h b/src/modules/musig/session_impl.h index fd09df6c8..d8dcd00c9 100644 --- a/src/modules/musig/session_impl.h +++ b/src/modules/musig/session_impl.h @@ -445,12 +445,18 @@ static int secp256k1_musig_nonce_gen_internal(const secp256k1_context* ctx, secp secp256k1_musig_secnonce_save(secnonce, k, &pk); secp256k1_musig_secnonce_invalidate(ctx, secnonce, !ret); + /* Compute pubnonce as two gejs */ for (i = 0; i < 2; i++) { secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &nonce_ptj[i], &k[i]); secp256k1_scalar_clear(&k[i]); - secp256k1_gej_clear(&nonce_ptj); } + + /* Batch convert to two public ges */ secp256k1_ge_set_all_gej(nonce_pts, nonce_ptj, 2); + for (i = 0; i < 2; i++) { + secp256k1_gej_clear(&nonce_ptj[i]); + } + for (i = 0; i < 2; i++) { secp256k1_declassify(ctx, &nonce_pts[i], sizeof(nonce_pts[i])); } From 59860bcc24814a4779be5688fce03bc6385faf87 Mon Sep 17 00:00:00 2001 From: Tim Ruffing Date: Mon, 10 Mar 2025 10:20:29 +0100 Subject: [PATCH 11/24] gha: Print all *.log files, in a separate action Before this commit, we didn't print *_example.log files and test_suite.log. Printing is now handled in a separate action, which avoids code duplication and makes the ci.yml file more readable. This changes the folding/grouping of the log output in the GitHub Actions CI, but I think the new variant is as good as the old one. Furthermore, the condition for printing the logs is changed from "always()" to "!cancelled()". This ensures that logs will still be printed if previous steps such as the CI script failed, but that they won't be printed if the entire run is cancelled (e.g., by clicking a button in the UI or through a force-push to the PR). This is in line with a recommendation in the GHA docs: https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/evaluate-expressions-in-workflows-and-actions#always --- .github/actions/print-logs/action.yml | 34 ++++ .github/workflows/ci.yml | 264 +++++--------------------- 2 files changed, 77 insertions(+), 221 deletions(-) create mode 100644 .github/actions/print-logs/action.yml diff --git a/.github/actions/print-logs/action.yml b/.github/actions/print-logs/action.yml new file mode 100644 index 000000000..33de35cb3 --- /dev/null +++ b/.github/actions/print-logs/action.yml @@ -0,0 +1,34 @@ +name: "Print logs" +description: "Print the log files produced by ci/ci.sh" +runs: + using: "composite" + steps: + - shell: bash + run: | + # Print the log files produced by ci/ci.sh + + # Helper functions + group() { + title=$1 + echo "::group::$title" + } + endgroup() { + echo "::endgroup::" + } + cat_file() { + file=$1 + group "$file" + cat "$file" + endgroup + } + + # Print all *.log files + shopt -s nullglob + for file in *.log; do + cat_file "$file" + done + + # Print environment + group "CI env" + env + endgroup diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 54b2fab1c..3683ebb08 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -107,23 +107,9 @@ jobs: dockerfile: ./ci/linux-debian.Dockerfile tag: linux-debian-image - - run: cat tests.log || true - if: ${{ always() }} - - run: cat noverify_tests.log || true - if: ${{ always() }} - - run: cat exhaustive_tests.log || true - if: ${{ always() }} - - run: cat ctime_tests.log || true - if: ${{ always() }} - - run: cat bench.log || true - if: ${{ always() }} - - run: cat config.log || true - if: ${{ always() }} - - run: cat test_env.log || true - if: ${{ always() }} - - name: CI env - run: env - if: ${{ always() }} + - name: Print logs + uses: ./.github/actions/print-logs + if: ${{ !cancelled() }} i686_debian: name: "i686: Linux (Debian stable)" @@ -157,23 +143,9 @@ jobs: dockerfile: ./ci/linux-debian.Dockerfile tag: linux-debian-image - - run: cat tests.log || true - if: ${{ always() }} - - run: cat noverify_tests.log || true - if: ${{ always() }} - - run: cat exhaustive_tests.log || true - if: ${{ always() }} - - run: cat ctime_tests.log || true - if: ${{ always() }} - - run: cat bench.log || true - if: ${{ always() }} - - run: cat config.log || true - if: ${{ always() }} - - run: cat test_env.log || true - if: ${{ always() }} - - name: CI env - run: env - if: ${{ always() }} + - name: Print logs + uses: ./.github/actions/print-logs + if: ${{ !cancelled() }} s390x_debian: name: "s390x (big-endian): Linux (Debian stable, QEMU)" @@ -203,23 +175,10 @@ jobs: dockerfile: ./ci/linux-debian.Dockerfile tag: linux-debian-image - - run: cat tests.log || true - if: ${{ always() }} - - run: cat noverify_tests.log || true - if: ${{ always() }} - - run: cat exhaustive_tests.log || true - if: ${{ always() }} - - run: cat ctime_tests.log || true - if: ${{ always() }} - - run: cat bench.log || true - if: ${{ always() }} - - run: cat config.log || true - if: ${{ always() }} - - run: cat test_env.log || true - if: ${{ always() }} - - name: CI env - run: env - if: ${{ always() }} + - name: Print logs + uses: ./.github/actions/print-logs + if: ${{ !cancelled() }} + arm32_debian: name: "ARM32: Linux (Debian stable, QEMU)" @@ -257,23 +216,9 @@ jobs: dockerfile: ./ci/linux-debian.Dockerfile tag: linux-debian-image - - run: cat tests.log || true - if: ${{ always() }} - - run: cat noverify_tests.log || true - if: ${{ always() }} - - run: cat exhaustive_tests.log || true - if: ${{ always() }} - - run: cat ctime_tests.log || true - if: ${{ always() }} - - run: cat bench.log || true - if: ${{ always() }} - - run: cat config.log || true - if: ${{ always() }} - - run: cat test_env.log || true - if: ${{ always() }} - - name: CI env - run: env - if: ${{ always() }} + - name: Print logs + uses: ./.github/actions/print-logs + if: ${{ !cancelled() }} arm64_debian: name: "ARM64: Linux (Debian stable, QEMU)" @@ -314,23 +259,9 @@ jobs: dockerfile: ./ci/linux-debian.Dockerfile tag: linux-debian-image - - run: cat tests.log || true - if: ${{ always() }} - - run: cat noverify_tests.log || true - if: ${{ always() }} - - run: cat exhaustive_tests.log || true - if: ${{ always() }} - - run: cat ctime_tests.log || true - if: ${{ always() }} - - run: cat bench.log || true - if: ${{ always() }} - - run: cat config.log || true - if: ${{ always() }} - - run: cat test_env.log || true - if: ${{ always() }} - - name: CI env - run: env - if: ${{ always() }} + - name: Print logs + uses: ./.github/actions/print-logs + if: ${{ !cancelled() }} ppc64le_debian: name: "ppc64le: Linux (Debian stable, QEMU)" @@ -360,23 +291,10 @@ jobs: dockerfile: ./ci/linux-debian.Dockerfile tag: linux-debian-image - - run: cat tests.log || true - if: ${{ always() }} - - run: cat noverify_tests.log || true - if: ${{ always() }} - - run: cat exhaustive_tests.log || true - if: ${{ always() }} - - run: cat ctime_tests.log || true - if: ${{ always() }} - - run: cat bench.log || true - if: ${{ always() }} - - run: cat config.log || true - if: ${{ always() }} - - run: cat test_env.log || true - if: ${{ always() }} - - name: CI env - run: env - if: ${{ always() }} + - name: Print logs + uses: ./.github/actions/print-logs + if: ${{ !cancelled() }} + valgrind_debian: name: "Valgrind (memcheck)" @@ -416,23 +334,9 @@ jobs: dockerfile: ./ci/linux-debian.Dockerfile tag: linux-debian-image - - run: cat tests.log || true - if: ${{ always() }} - - run: cat noverify_tests.log || true - if: ${{ always() }} - - run: cat exhaustive_tests.log || true - if: ${{ always() }} - - run: cat ctime_tests.log || true - if: ${{ always() }} - - run: cat bench.log || true - if: ${{ always() }} - - run: cat config.log || true - if: ${{ always() }} - - run: cat test_env.log || true - if: ${{ always() }} - - name: CI env - run: env - if: ${{ always() }} + - name: Print logs + uses: ./.github/actions/print-logs + if: ${{ !cancelled() }} sanitizers_debian: name: "UBSan, ASan, LSan" @@ -473,23 +377,9 @@ jobs: dockerfile: ./ci/linux-debian.Dockerfile tag: linux-debian-image - - run: cat tests.log || true - if: ${{ always() }} - - run: cat noverify_tests.log || true - if: ${{ always() }} - - run: cat exhaustive_tests.log || true - if: ${{ always() }} - - run: cat ctime_tests.log || true - if: ${{ always() }} - - run: cat bench.log || true - if: ${{ always() }} - - run: cat config.log || true - if: ${{ always() }} - - run: cat test_env.log || true - if: ${{ always() }} - - name: CI env - run: env - if: ${{ always() }} + - name: Print logs + uses: ./.github/actions/print-logs + if: ${{ !cancelled() }} msan_debian: name: "MSan" @@ -537,23 +427,10 @@ jobs: dockerfile: ./ci/linux-debian.Dockerfile tag: linux-debian-image - - run: cat tests.log || true - if: ${{ always() }} - - run: cat noverify_tests.log || true - if: ${{ always() }} - - run: cat exhaustive_tests.log || true - if: ${{ always() }} - - run: cat ctime_tests.log || true - if: ${{ always() }} - - run: cat bench.log || true - if: ${{ always() }} - - run: cat config.log || true - if: ${{ always() }} - - run: cat test_env.log || true - if: ${{ always() }} - - name: CI env - run: env - if: ${{ always() }} + - name: Print logs + uses: ./.github/actions/print-logs + if: ${{ !cancelled() }} + mingw_debian: name: ${{ matrix.configuration.job_name }} @@ -593,23 +470,9 @@ jobs: dockerfile: ./ci/linux-debian.Dockerfile tag: linux-debian-image - - run: cat tests.log || true - if: ${{ always() }} - - run: cat noverify_tests.log || true - if: ${{ always() }} - - run: cat exhaustive_tests.log || true - if: ${{ always() }} - - run: cat ctime_tests.log || true - if: ${{ always() }} - - run: cat bench.log || true - if: ${{ always() }} - - run: cat config.log || true - if: ${{ always() }} - - run: cat test_env.log || true - if: ${{ always() }} - - name: CI env - run: env - if: ${{ always() }} + - name: Print logs + uses: ./.github/actions/print-logs + if: ${{ !cancelled() }} x86_64-macos-native: name: "x86_64: macOS Ventura, Valgrind" @@ -652,23 +515,9 @@ jobs: env: ${{ matrix.env_vars }} run: ./ci/ci.sh - - run: cat tests.log || true - if: ${{ always() }} - - run: cat noverify_tests.log || true - if: ${{ always() }} - - run: cat exhaustive_tests.log || true - if: ${{ always() }} - - run: cat ctime_tests.log || true - if: ${{ always() }} - - run: cat bench.log || true - if: ${{ always() }} - - run: cat config.log || true - if: ${{ always() }} - - run: cat test_env.log || true - if: ${{ always() }} - - name: CI env - run: env - if: ${{ always() }} + - name: Print logs + uses: ./.github/actions/print-logs + if: ${{ !cancelled() }} arm64-macos-native: name: "ARM64: macOS Sonoma" @@ -708,23 +557,10 @@ jobs: env: ${{ matrix.env_vars }} run: ./ci/ci.sh - - run: cat tests.log || true - if: ${{ always() }} - - run: cat noverify_tests.log || true - if: ${{ always() }} - - run: cat exhaustive_tests.log || true - if: ${{ always() }} - - run: cat ctime_tests.log || true - if: ${{ always() }} - - run: cat bench.log || true - if: ${{ always() }} - - run: cat config.log || true - if: ${{ always() }} - - run: cat test_env.log || true - if: ${{ always() }} - - name: CI env - run: env - if: ${{ always() }} + - name: Print logs + uses: ./.github/actions/print-logs + if: ${{ !cancelled() }} + win64-native: name: ${{ matrix.configuration.job_name }} @@ -813,23 +649,9 @@ jobs: dockerfile: ./ci/linux-debian.Dockerfile tag: linux-debian-image - - run: cat tests.log || true - if: ${{ always() }} - - run: cat noverify_tests.log || true - if: ${{ always() }} - - run: cat exhaustive_tests.log || true - if: ${{ always() }} - - run: cat ctime_tests.log || true - if: ${{ always() }} - - run: cat bench.log || true - if: ${{ always() }} - - run: cat config.log || true - if: ${{ always() }} - - run: cat test_env.log || true - if: ${{ always() }} - - name: CI env - run: env - if: ${{ always() }} + - name: Print logs + uses: ./.github/actions/print-logs + if: ${{ !cancelled() }} cxx_headers_debian: name: "C++ (public headers)" From 88548058b3e88f7f1ce7c1abbe12da8105a858cc Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Mon, 10 Mar 2025 11:22:13 +0000 Subject: [PATCH 12/24] Introduce `SECP256K1_LOCAL_VAR` macro This change makes the `-fvisibility=hidden` compiler option unnecessary. --- Makefile.am | 1 + src/precomputed_ecmult.h | 6 ++++-- src/precomputed_ecmult_gen.h | 4 +++- src/util_local_visibility.h | 12 ++++++++++++ 4 files changed, 20 insertions(+), 3 deletions(-) create mode 100644 src/util_local_visibility.h diff --git a/Makefile.am b/Makefile.am index a95b4809d..fb4a48aa8 100644 --- a/Makefile.am +++ b/Makefile.am @@ -47,6 +47,7 @@ noinst_HEADERS += src/assumptions.h noinst_HEADERS += src/checkmem.h noinst_HEADERS += src/testutil.h noinst_HEADERS += src/util.h +noinst_HEADERS += src/util_local_visibility.h noinst_HEADERS += src/int128.h noinst_HEADERS += src/int128_impl.h noinst_HEADERS += src/int128_native.h diff --git a/src/precomputed_ecmult.h b/src/precomputed_ecmult.h index 17df10296..e5a85f684 100644 --- a/src/precomputed_ecmult.h +++ b/src/precomputed_ecmult.h @@ -13,6 +13,8 @@ extern "C" { #include "ecmult.h" #include "group.h" +#include "util_local_visibility.h" + #if defined(EXHAUSTIVE_TEST_ORDER) # if EXHAUSTIVE_TEST_ORDER == 7 # define WINDOW_G 3 @@ -27,8 +29,8 @@ static secp256k1_ge_storage secp256k1_pre_g[ECMULT_TABLE_SIZE(WINDOW_G)]; static secp256k1_ge_storage secp256k1_pre_g_128[ECMULT_TABLE_SIZE(WINDOW_G)]; #else /* !defined(EXHAUSTIVE_TEST_ORDER) */ # define WINDOW_G ECMULT_WINDOW_SIZE -extern const secp256k1_ge_storage secp256k1_pre_g[ECMULT_TABLE_SIZE(WINDOW_G)]; -extern const secp256k1_ge_storage secp256k1_pre_g_128[ECMULT_TABLE_SIZE(WINDOW_G)]; +SECP256K1_LOCAL_VAR const secp256k1_ge_storage secp256k1_pre_g[ECMULT_TABLE_SIZE(WINDOW_G)]; +SECP256K1_LOCAL_VAR const secp256k1_ge_storage secp256k1_pre_g_128[ECMULT_TABLE_SIZE(WINDOW_G)]; #endif /* defined(EXHAUSTIVE_TEST_ORDER) */ #ifdef __cplusplus diff --git a/src/precomputed_ecmult_gen.h b/src/precomputed_ecmult_gen.h index 283738a5c..00ddce108 100644 --- a/src/precomputed_ecmult_gen.h +++ b/src/precomputed_ecmult_gen.h @@ -13,10 +13,12 @@ extern "C" { #include "group.h" #include "ecmult_gen.h" +#include "util_local_visibility.h" + #ifdef EXHAUSTIVE_TEST_ORDER static secp256k1_ge_storage secp256k1_ecmult_gen_prec_table[COMB_BLOCKS][COMB_POINTS]; #else -extern const secp256k1_ge_storage secp256k1_ecmult_gen_prec_table[COMB_BLOCKS][COMB_POINTS]; +SECP256K1_LOCAL_VAR const secp256k1_ge_storage secp256k1_ecmult_gen_prec_table[COMB_BLOCKS][COMB_POINTS]; #endif /* defined(EXHAUSTIVE_TEST_ORDER) */ #ifdef __cplusplus diff --git a/src/util_local_visibility.h b/src/util_local_visibility.h new file mode 100644 index 000000000..8912a64d1 --- /dev/null +++ b/src/util_local_visibility.h @@ -0,0 +1,12 @@ +#ifndef SECP256K1_LOCAL_VISIBILITY_H +#define SECP256K1_LOCAL_VISIBILITY_H + +/* Global variable visibility */ +/* See: https://github.com/bitcoin-core/secp256k1/issues/1181 */ +#if !defined(_WIN32) && defined(__GNUC__) && (__GNUC__ >= 4) +# define SECP256K1_LOCAL_VAR extern __attribute__ ((visibility ("hidden"))) +#else +# define SECP256K1_LOCAL_VAR extern +#endif + +#endif /* SECP256K1_LOCAL_VISIBILITY_H */ From 41d32ab2de050e48f2854bf381cc86871aa59135 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Mon, 10 Mar 2025 11:22:25 +0000 Subject: [PATCH 13/24] test: Add `tools/symbol-check.py` Co-authored-by: Tim Ruffing --- tools/symbol-check.py | 72 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100755 tools/symbol-check.py diff --git a/tools/symbol-check.py b/tools/symbol-check.py new file mode 100755 index 000000000..e7f478082 --- /dev/null +++ b/tools/symbol-check.py @@ -0,0 +1,72 @@ +#!/usr/bin/env python3 +"""Check that a libsecp256k1 shared library exports only expected symbols. + +Usage examples: + - When building with Autotools: + ./tools/symbol-check.py .libs/libsecp256k1.so + ./tools/symbol-check.py .libs/libsecp256k1-.dll + ./tools/symbol-check.py .libs/libsecp256k1.dylib + + - When building with CMake: + ./tools/symbol-check.py build/lib/libsecp256k1.so + ./tools/symbol-check.py build/bin/libsecp256k1-.dll + ./tools/symbol-check.py build/lib/libsecp256k1.dylib""" + +import re +import sys +import subprocess + +import lief + + +class UnexpectedExport(RuntimeError): + pass + + +def get_exported_exports(library) -> list[str]: + """Adapter function to get exported symbols based on the library format.""" + if library.format == lief.Binary.FORMATS.ELF: + return [symbol.name for symbol in library.exported_symbols] + elif library.format == lief.Binary.FORMATS.PE: + return [entry.name for entry in library.get_export().entries] + elif library.format == lief.Binary.FORMATS.MACHO: + return [symbol.name[1:] for symbol in library.exported_symbols] + raise NotImplementedError(f"Unsupported format: {library.format}") + + +def grep_expected_symbols() -> list[str]: + """Guess the list of expected exported symbols from the source code.""" + grep_output = subprocess.check_output( + ["git", "grep", r"^\s*SECP256K1_API", "--", "include"], + universal_newlines=True, + encoding="utf-8" + ) + lines = grep_output.split("\n") + pattern = re.compile(r'\bsecp256k1_\w+') + exported: list[str] = [pattern.findall(line)[-1] for line in lines if line.strip()] + return exported + + +def check_symbols(library, expected_exports) -> None: + """Check that the library exports only the expected symbols.""" + actual_exports = get_exported_exports(library) + unexpected_exports = set(actual_exports) - set(expected_exports) + if unexpected_exports != set(): + raise UnexpectedExport(f"Unexpected exported symbols: {unexpected_exports}") + +def main(): + if len(sys.argv) != 2: + print(__doc__) + return 1 + library = lief.parse(sys.argv[1]) + expected_exports = grep_expected_symbols() + try: + check_symbols(library, expected_exports) + except UnexpectedExport as e: + print(f"{sys.argv[0]}: In {sys.argv[1]}: {e}") + return 1 + return 0 + + +if __name__ == "__main__": + sys.exit(main()) From 8ed1d83d92d19bd1c9ce5575e3858f881cc1674a Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Mon, 10 Mar 2025 11:22:38 +0000 Subject: [PATCH 14/24] ci: Run `tools/symbol-check.py` --- .cirrus.yml | 3 +++ .github/workflows/ci.yml | 29 +++++++++++++++++++++++++++++ ci/ci.sh | 16 +++++++++++++++- ci/linux-debian.Dockerfile | 6 +++++- 4 files changed, 52 insertions(+), 2 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index 81a4f0432..023cd1916 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -29,6 +29,8 @@ env: BENCH: yes SECP256K1_BENCH_ITERS: 2 CTIMETESTS: yes + SYMBOL_CHECK: yes + VIRTUAL_ENV: /root/venv # Compile and run the tests EXAMPLES: yes @@ -53,6 +55,7 @@ cat_logs_snippet: &CAT_LOGS linux_arm64_container_snippet: &LINUX_ARM64_CONTAINER env_script: + - export PATH="$VIRTUAL_ENV/bin:$PATH" - env | tee /tmp/env build_script: - DOCKER_BUILDKIT=1 docker build --file "ci/linux-debian.Dockerfile" --tag="ci_secp256k1_arm" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2a3f6dc2f..a3108d6bb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -40,6 +40,7 @@ env: BENCH: 'yes' SECP256K1_BENCH_ITERS: 2 CTIMETESTS: 'yes' + SYMBOL_CHECK: 'yes' # Compile and run the examples. EXAMPLES: 'yes' @@ -365,6 +366,7 @@ jobs: ASAN_OPTIONS: 'strict_string_checks=1:detect_stack_use_after_return=1:detect_leaks=1' LSAN_OPTIONS: 'use_unaligned=1' SECP256K1_TEST_ITERS: 32 + SYMBOL_CHECK: 'no' steps: - name: Checkout @@ -415,6 +417,7 @@ jobs: SECP256K1_TEST_ITERS: 32 ASM: 'no' WITH_VALGRIND: 'no' + SYMBOL_CHECK: 'no' steps: - name: Checkout @@ -483,6 +486,7 @@ jobs: CC: 'clang' HOMEBREW_NO_AUTO_UPDATE: 1 HOMEBREW_NO_INSTALL_CLEANUP: 1 + SYMBOL_CHECK: 'no' strategy: fail-fast: false @@ -515,6 +519,12 @@ jobs: env: ${{ matrix.env_vars }} run: ./ci/ci.sh + - name: Symbol check + run: | + python3 --version + python3 -m pip install lief + python3 ./tools/symbol-check.py .libs/libsecp256k1.dylib + - name: Print logs uses: ./.github/actions/print-logs if: ${{ !cancelled() }} @@ -530,6 +540,7 @@ jobs: HOMEBREW_NO_INSTALL_CLEANUP: 1 WITH_VALGRIND: 'no' CTIMETESTS: 'no' + SYMBOL_CHECK: 'no' strategy: fail-fast: false @@ -557,6 +568,16 @@ jobs: env: ${{ matrix.env_vars }} run: ./ci/ci.sh + - name: Symbol check + env: + VIRTUAL_ENV: '${{ github.workspace }}/venv' + run: | + python3 --version + python3 -m venv $VIRTUAL_ENV + export PATH="$VIRTUAL_ENV/bin:$PATH" + python3 -m pip install lief + python3 ./tools/symbol-check.py .libs/libsecp256k1.dylib + - name: Print logs uses: ./.github/actions/print-logs if: ${{ !cancelled() }} @@ -573,6 +594,7 @@ jobs: configuration: - job_name: 'x64 (MSVC): Windows (VS 2022, shared)' cmake_options: '-A x64 -DBUILD_SHARED_LIBS=ON' + symbol_check: 'true' - job_name: 'x64 (MSVC): Windows (VS 2022, static)' cmake_options: '-A x64 -DBUILD_SHARED_LIBS=OFF' - job_name: 'x64 (MSVC): Windows (VS 2022, int128_struct)' @@ -601,6 +623,13 @@ jobs: run: | cd build/bin/RelWithDebInfo && file *tests.exe bench*.exe libsecp256k1-*.dll || true + - name: Symbol check + if: ${{ matrix.configuration.symbol_check }} + run: | + py -3 --version + py -3 -m pip install lief + py -3 .\tools\symbol-check.py build\bin\RelWithDebInfo\libsecp256k1-5.dll + - name: Check run: | ctest -C RelWithDebInfo --test-dir build -j ([int]$env:NUMBER_OF_PROCESSORS + 1) diff --git a/ci/ci.sh b/ci/ci.sh index 3636deafa..f50a5f075 100755 --- a/ci/ci.sh +++ b/ci/ci.sh @@ -14,7 +14,7 @@ print_environment() { for var in WERROR_CFLAGS MAKEFLAGS BUILD \ ECMULTWINDOW ECMULTGENKB ASM WIDEMUL WITH_VALGRIND EXTRAFLAGS \ EXPERIMENTAL ECDH RECOVERY EXTRAKEYS MUSIG SCHNORRSIG ELLSWIFT \ - SECP256K1_TEST_ITERS BENCH SECP256K1_BENCH_ITERS CTIMETESTS\ + SECP256K1_TEST_ITERS BENCH SECP256K1_BENCH_ITERS CTIMETESTS SYMBOL_CHECK \ EXAMPLES \ HOST WRAPPER_CMD \ CC CFLAGS CPPFLAGS AR NM \ @@ -107,6 +107,20 @@ file *tests* || true file bench* || true file .libs/* || true +if [ "$SYMBOL_CHECK" = "yes" ] +then + python3 --version + case "$HOST" in + *mingw*) + ls -l .libs + python3 ./tools/symbol-check.py .libs/libsecp256k1-5.dll + ;; + *) + python3 ./tools/symbol-check.py .libs/libsecp256k1.so + ;; + esac +fi + # This tells `make check` to wrap test invocations. export LOG_COMPILER="$WRAPPER_CMD" diff --git a/ci/linux-debian.Dockerfile b/ci/linux-debian.Dockerfile index 241bfa971..547b40223 100644 --- a/ci/linux-debian.Dockerfile +++ b/ci/linux-debian.Dockerfile @@ -32,7 +32,7 @@ RUN apt-get update && apt-get install --no-install-recommends -y \ gcc-powerpc64le-linux-gnu libc6-dev-ppc64el-cross libc6-dbg:ppc64el \ gcc-mingw-w64-x86-64-win32 wine64 wine \ gcc-mingw-w64-i686-win32 wine32 \ - python3 && \ + python3-full && \ if ! ( dpkg --print-architecture | grep --quiet "arm64" ) ; then \ apt-get install --no-install-recommends -y \ gcc-aarch64-linux-gnu libc6-dev-arm64-cross libc6-dbg:arm64 ;\ @@ -77,3 +77,7 @@ RUN \ apt-get autoremove -y wget && \ apt-get clean && rm -rf /var/lib/apt/lists/* +ENV VIRTUAL_ENV=/root/venv +RUN python3 -m venv $VIRTUAL_ENV +ENV PATH="$VIRTUAL_ENV/bin:$PATH" +RUN pip install lief From d1478763a5f400fafb42af5911db4a9460dd4a5d Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Mon, 10 Mar 2025 11:22:45 +0000 Subject: [PATCH 15/24] build: Drop no longer needed `-fvisibility=hidden` compiler option --- CMakeLists.txt | 2 -- configure.ac | 1 - 2 files changed, 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 520a96efd..2b7737146 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -271,8 +271,6 @@ else() try_append_c_flags(-Wundef) endif() -set(CMAKE_C_VISIBILITY_PRESET hidden) - set(print_msan_notice) if(SECP256K1_BUILD_CTIME_TESTS) include(CheckMemorySanitizer) diff --git a/configure.ac b/configure.ac index c62a391d7..8cb8006c5 100644 --- a/configure.ac +++ b/configure.ac @@ -111,7 +111,6 @@ AC_DEFUN([SECP_TRY_APPEND_DEFAULT_CFLAGS], [ SECP_TRY_APPEND_CFLAGS([-Wcast-align=strict], $1) # GCC >= 8.0 SECP_TRY_APPEND_CFLAGS([-Wconditional-uninitialized], $1) # Clang >= 3.0 only SECP_TRY_APPEND_CFLAGS([-Wreserved-identifier], $1) # Clang >= 13.0 only - SECP_TRY_APPEND_CFLAGS([-fvisibility=hidden], $1) # GCC >= 4.0 CFLAGS="$SECP_TRY_APPEND_DEFAULT_CFLAGS_saved_CFLAGS" fi From 51907fa91875b8fd34cb23ec6c23793f7ea92949 Mon Sep 17 00:00:00 2001 From: Jonas Nick Date: Thu, 13 Mar 2025 08:01:08 +0000 Subject: [PATCH 16/24] tests: remove unused uncounting_illegal_callback_fn This callback function has been unused since a1d52e3e125bb46dac2cf6daa699e9f15167e8d4 --- src/tests.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/tests.c b/src/tests.c index 06bcc5956..52614401c 100644 --- a/src/tests.c +++ b/src/tests.c @@ -87,15 +87,6 @@ static void counting_callback_fn(const char* str, void* data) { (*p)++; } -static void uncounting_illegal_callback_fn(const char* str, void* data) { - /* Dummy callback function that just counts (backwards). */ - int32_t *p; - (void)str; - p = data; - CHECK(*p != INT32_MIN); - (*p)--; -} - static void run_xoshiro256pp_tests(void) { { size_t i; From 1b6e081538cc9a171157ec858c4aac19deb7d6cc Mon Sep 17 00:00:00 2001 From: Jonas Nick Date: Thu, 13 Mar 2025 09:31:02 +0000 Subject: [PATCH 17/24] include: remove WARN_UNUSED_RESULT for functions always returning 1 This makes the usage of the atribute consistent. In the musig and ellswift module, functions that return 1 always already don't have the WARN_UNUSED_RESULT attribute. In secp256k1.h and the extrakeys module, this has only been the case partially. In all cases where this was removed, the function only returns 0 if the illegal callback has been called. --- include/secp256k1.h | 4 ++-- include/secp256k1_extrakeys.h | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/secp256k1.h b/include/secp256k1.h index 2477de49e..1d25a02ab 100644 --- a/include/secp256k1.h +++ b/include/secp256k1.h @@ -707,7 +707,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_negate( * Args: ctx: pointer to a context object * In/Out: pubkey: pointer to the public key to be negated. */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_negate( +SECP256K1_API int secp256k1_ec_pubkey_negate( const secp256k1_context *ctx, secp256k1_pubkey *pubkey ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); @@ -857,7 +857,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_combine( * msg: pointer to an array containing the message * msglen: length of the message array */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_tagged_sha256( +SECP256K1_API int secp256k1_tagged_sha256( const secp256k1_context *ctx, unsigned char *hash32, const unsigned char *tag, diff --git a/include/secp256k1_extrakeys.h b/include/secp256k1_extrakeys.h index 48c98693c..1a517ded9 100644 --- a/include/secp256k1_extrakeys.h +++ b/include/secp256k1_extrakeys.h @@ -90,7 +90,7 @@ SECP256K1_API int secp256k1_xonly_pubkey_cmp( * the negation of the pubkey and set to 0 otherwise. * In: pubkey: pointer to a public key that is converted. */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_from_pubkey( +SECP256K1_API int secp256k1_xonly_pubkey_from_pubkey( const secp256k1_context *ctx, secp256k1_xonly_pubkey *xonly_pubkey, int *pk_parity, @@ -179,7 +179,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_create( * Out: seckey: pointer to a 32-byte buffer for the secret key. * In: keypair: pointer to a keypair. */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_sec( +SECP256K1_API int secp256k1_keypair_sec( const secp256k1_context *ctx, unsigned char *seckey, const secp256k1_keypair *keypair @@ -192,7 +192,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_sec( * Out: pubkey: pointer to a pubkey object, set to the keypair public key. * In: keypair: pointer to a keypair. */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_pub( +SECP256K1_API int secp256k1_keypair_pub( const secp256k1_context *ctx, secp256k1_pubkey *pubkey, const secp256k1_keypair *keypair @@ -211,7 +211,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_pub( * pk_parity argument of secp256k1_xonly_pubkey_from_pubkey. * In: keypair: pointer to a keypair. */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_xonly_pub( +SECP256K1_API int secp256k1_keypair_xonly_pub( const secp256k1_context *ctx, secp256k1_xonly_pubkey *pubkey, int *pk_parity, From d87c3bc58f369a91fb07d0812eec8b0d77e8968b Mon Sep 17 00:00:00 2001 From: Tim Ruffing Date: Thu, 13 Mar 2025 11:56:07 +0100 Subject: [PATCH 18/24] ci: Fix exiting from ci.sh on error Fixes the following bash error when make fails: ./ci/ci.sh: line 100: return: can only `return' from a function or sourced script --- ci/ci.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ci/ci.sh b/ci/ci.sh index f50a5f075..3285ecc95 100755 --- a/ci/ci.sh +++ b/ci/ci.sh @@ -94,10 +94,10 @@ if [ $build_exit_code -ne 0 ]; then *snapshot*) # Ignore internal compiler errors in gcc-snapshot and clang-snapshot grep -e "internal compiler error:" -e "PLEASE submit a bug report" make.log - return $?; + exit $? ;; *) - return 1; + exit 1 ;; esac fi From 20b05c9d3f3376fa3719b3d455de93423167244c Mon Sep 17 00:00:00 2001 From: Tim Ruffing Date: Thu, 13 Mar 2025 12:56:21 +0100 Subject: [PATCH 19/24] configure: Show exhaustive tests in summary Fixes #1658. --- configure.ac | 1 + 1 file changed, 1 insertion(+) diff --git a/configure.ac b/configure.ac index 8cb8006c5..406227fcd 100644 --- a/configure.ac +++ b/configure.ac @@ -476,6 +476,7 @@ echo "Build Options:" echo " with external callbacks = $enable_external_default_callbacks" echo " with benchmarks = $enable_benchmark" echo " with tests = $enable_tests" +echo " with exhaustive tests = $enable_exhaustive_tests" echo " with ctime tests = $enable_ctime_tests" echo " with coverage = $enable_coverage" echo " with examples = $enable_examples" From a33108b84e10fde56b544a2dbfabc4ec8a183fce Mon Sep 17 00:00:00 2001 From: mllwchrry Date: Tue, 17 Feb 2026 12:16:54 +0200 Subject: [PATCH 20/24] schnorrsig_halfagg: Add missing static keyword to internal function --- src/modules/schnorrsig_halfagg/main_impl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/schnorrsig_halfagg/main_impl.h b/src/modules/schnorrsig_halfagg/main_impl.h index 0d3662ba7..af612195b 100644 --- a/src/modules/schnorrsig_halfagg/main_impl.h +++ b/src/modules/schnorrsig_halfagg/main_impl.h @@ -8,7 +8,7 @@ /* Initializes SHA256 with fixed midstate. This midstate was computed by applying * SHA256 to SHA256("HalfAgg/randomizer")||SHA256("HalfAgg/randomizer"). */ -void secp256k1_schnorrsig_sha256_tagged_aggregation(secp256k1_sha256 *sha) { +static void secp256k1_schnorrsig_sha256_tagged_aggregation(secp256k1_sha256 *sha) { secp256k1_sha256_initialize(sha); sha->s[0] = 0xd11f5532ul; sha->s[1] = 0xfa57f70ful; From 92dfca3199b446a5fdff41a39ff308ae92dda777 Mon Sep 17 00:00:00 2001 From: mllwchrry Date: Tue, 17 Feb 2026 12:37:04 +0200 Subject: [PATCH 21/24] Port bitcoin-core/secp256k1#1642 to zkp-specific code --- src/modules/ecdsa_adaptor/main_impl.h | 2 +- src/modules/whitelist/whitelist_impl.h | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/modules/ecdsa_adaptor/main_impl.h b/src/modules/ecdsa_adaptor/main_impl.h index 5d16e0117..25232b488 100644 --- a/src/modules/ecdsa_adaptor/main_impl.h +++ b/src/modules/ecdsa_adaptor/main_impl.h @@ -341,7 +341,7 @@ int secp256k1_ecdsa_adaptor_recover(const secp256k1_context* ctx, unsigned char /* 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)); - if (!secp256k1_eckey_pubkey_serialize(&enckey_expected_ge, enckey_expected33, &size, SECP256K1_EC_COMPRESSED)) { + if (!secp256k1_eckey_pubkey_serialize(&enckey_expected_ge, enckey_expected33, &size, 1)) { /* Unreachable from tests (and other VERIFY builds) and therefore this * branch should be ignored in test coverage analysis. * diff --git a/src/modules/whitelist/whitelist_impl.h b/src/modules/whitelist/whitelist_impl.h index 48f8bcca6..bb244907f 100644 --- a/src/modules/whitelist/whitelist_impl.h +++ b/src/modules/whitelist/whitelist_impl.h @@ -18,7 +18,7 @@ static int secp256k1_whitelist_hash_pubkey(secp256k1_scalar* output, secp256k1_g secp256k1_ge_set_gej(&ge, pubkey); secp256k1_sha256_initialize(&sha); - if (!secp256k1_eckey_pubkey_serialize(&ge, c, &size, SECP256K1_EC_COMPRESSED)) { + if (!secp256k1_eckey_pubkey_serialize(&ge, c, &size, 1)) { return 0; } secp256k1_sha256_write(&sha, c, size); @@ -95,7 +95,7 @@ static int secp256k1_whitelist_compute_keys_and_message(const secp256k1_context* secp256k1_pubkey_load(ctx, &subkey_ge, sub_pubkey); /* commit to sub-key */ - if (!secp256k1_eckey_pubkey_serialize(&subkey_ge, c, &size, SECP256K1_EC_COMPRESSED)) { + if (!secp256k1_eckey_pubkey_serialize(&subkey_ge, c, &size, 1)) { return 0; } secp256k1_sha256_write(&sha, c, size); @@ -106,12 +106,12 @@ static int secp256k1_whitelist_compute_keys_and_message(const secp256k1_context* /* commit to fixed keys */ secp256k1_pubkey_load(ctx, &offline_ge, &offline_pubkeys[i]); - if (!secp256k1_eckey_pubkey_serialize(&offline_ge, c, &size, SECP256K1_EC_COMPRESSED)) { + if (!secp256k1_eckey_pubkey_serialize(&offline_ge, c, &size, 1)) { return 0; } secp256k1_sha256_write(&sha, c, size); secp256k1_pubkey_load(ctx, &online_ge, &online_pubkeys[i]); - if (!secp256k1_eckey_pubkey_serialize(&online_ge, c, &size, SECP256K1_EC_COMPRESSED)) { + if (!secp256k1_eckey_pubkey_serialize(&online_ge, c, &size, 1)) { return 0; } secp256k1_sha256_write(&sha, c, size); From 8238a1a01b871eecf5d8d30257bf6933b8acf872 Mon Sep 17 00:00:00 2001 From: Tim Ruffing Date: Mon, 21 Jul 2025 16:35:16 +0200 Subject: [PATCH 22/24] ci: Don't hardcode ABI version --- .github/workflows/ci.yml | 3 ++- ci/ci.sh | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a930e997a..9e25a909b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -704,10 +704,11 @@ jobs: - name: Symbol check if: ${{ matrix.configuration.symbol_check }} + shell: bash run: | py -3 --version py -3 -m pip install lief - py -3 .\tools\symbol-check.py build\bin\RelWithDebInfo\libsecp256k1-5.dll + py -3 ./tools/symbol-check.py build/bin/RelWithDebInfo/libsecp256k1-*.dll - name: Check run: | diff --git a/ci/ci.sh b/ci/ci.sh index 843107bd6..5921415fa 100755 --- a/ci/ci.sh +++ b/ci/ci.sh @@ -118,7 +118,7 @@ then case "$HOST" in *mingw*) ls -l .libs - python3 ./tools/symbol-check.py .libs/libsecp256k1-5.dll + python3 ./tools/symbol-check.py .libs/libsecp256k1-*.dll ;; *) python3 ./tools/symbol-check.py .libs/libsecp256k1.so From 5092b85bad87727cbb6175376dc37a4959d7abd2 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Wed, 15 Oct 2025 15:31:21 +0100 Subject: [PATCH 23/24] ci: Switch to macOS 15 Sequoia Intel-based image The `macos-13` image has been deprecated and will be unavailable soon. See: https://github.com/actions/runner-images/issues/13045. --- .github/workflows/ci.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9e25a909b..e255fe6e3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -557,9 +557,8 @@ jobs: if: ${{ !cancelled() }} x86_64-macos-native: - name: "x86_64: macOS Ventura, Valgrind" - # See: https://github.com/actions/runner-images#available-images. - runs-on: macos-13 + name: "x86_64: macOS Sequoia, Valgrind" + runs-on: macos-15-intel env: CC: 'clang' From 3e5a5b8c65473c4793ca4474cf5565bde183d2d1 Mon Sep 17 00:00:00 2001 From: mllwchrry Date: Mon, 23 Feb 2026 12:38:51 +0200 Subject: [PATCH 24/24] ci: Use venv for pip install on x86_64 macOS --- .github/workflows/ci.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e255fe6e3..b39223558 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -598,8 +598,12 @@ jobs: run: ./ci/ci.sh - name: Symbol check + env: + VIRTUAL_ENV: '${{ github.workspace }}/venv' run: | python3 --version + python3 -m venv $VIRTUAL_ENV + export PATH="$VIRTUAL_ENV/bin:$PATH" python3 -m pip install lief python3 ./tools/symbol-check.py .libs/libsecp256k1.dylib