From d93f62e3693d6763891edcad11472f9d475177e5 Mon Sep 17 00:00:00 2001 From: Tim Ruffing Date: Wed, 1 Feb 2023 11:37:39 +0100 Subject: [PATCH 001/100] field: Verify field element even after secp256k1_fe_set_b32 fails --- src/field_10x26_impl.h | 1 + src/field_5x52_impl.h | 1 + 2 files changed, 2 insertions(+) diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h index 5e6c63cf4e..2c10814fa8 100644 --- a/src/field_10x26_impl.h +++ b/src/field_10x26_impl.h @@ -372,6 +372,7 @@ static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a) { secp256k1_fe_verify(r); } else { r->normalized = 0; + secp256k1_fe_verify(r); } #endif return ret; diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h index 985c486ae3..d92def5c33 100644 --- a/src/field_5x52_impl.h +++ b/src/field_5x52_impl.h @@ -347,6 +347,7 @@ static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a) { secp256k1_fe_verify(r); } else { r->normalized = 0; + secp256k1_fe_verify(r); } #endif return ret; From ca92a35d019730aec9d3ec8097dcbb9633a69874 Mon Sep 17 00:00:00 2001 From: Tim Ruffing Date: Wed, 1 Feb 2023 11:44:28 +0100 Subject: [PATCH 002/100] field: Simplify code in secp256k1_fe_set_b32 --- src/field_10x26_impl.h | 9 ++------- src/field_5x52_impl.h | 9 ++------- 2 files changed, 4 insertions(+), 14 deletions(-) diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h index 2c10814fa8..9fd8de808d 100644 --- a/src/field_10x26_impl.h +++ b/src/field_10x26_impl.h @@ -367,13 +367,8 @@ static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a) { ret = !((r->n[9] == 0x3FFFFFUL) & ((r->n[8] & r->n[7] & r->n[6] & r->n[5] & r->n[4] & r->n[3] & r->n[2]) == 0x3FFFFFFUL) & ((r->n[1] + 0x40UL + ((r->n[0] + 0x3D1UL) >> 26)) > 0x3FFFFFFUL)); #ifdef VERIFY r->magnitude = 1; - if (ret) { - r->normalized = 1; - secp256k1_fe_verify(r); - } else { - r->normalized = 0; - secp256k1_fe_verify(r); - } + r->normalized = ret; + secp256k1_fe_verify(r); #endif return ret; } diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h index d92def5c33..4262542fc1 100644 --- a/src/field_5x52_impl.h +++ b/src/field_5x52_impl.h @@ -342,13 +342,8 @@ static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a) { ret = !((r->n[4] == 0x0FFFFFFFFFFFFULL) & ((r->n[3] & r->n[2] & r->n[1]) == 0xFFFFFFFFFFFFFULL) & (r->n[0] >= 0xFFFFEFFFFFC2FULL)); #ifdef VERIFY r->magnitude = 1; - if (ret) { - r->normalized = 1; - secp256k1_fe_verify(r); - } else { - r->normalized = 0; - secp256k1_fe_verify(r); - } + r->normalized = ret; + secp256k1_fe_verify(r); #endif return ret; } From 77445898a5852ecd38ab95cfb329333a82673115 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Thu, 9 Mar 2023 13:05:14 +0000 Subject: [PATCH 003/100] Remove `SECP256K1_INLINE` usage from examples --- examples/examples_util.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/examples_util.h b/examples/examples_util.h index a52b1fa115..c4bd67b7f6 100644 --- a/examples/examples_util.h +++ b/examples/examples_util.h @@ -77,7 +77,7 @@ static void print_hex(unsigned char* data, size_t size) { #include #endif /* Cleanses memory to prevent leaking sensitive info. Won't be optimized out. */ -static SECP256K1_INLINE void secure_erase(void *ptr, size_t len) { +static void secure_erase(void *ptr, size_t len) { #if defined(_MSC_VER) /* SecureZeroMemory is guaranteed not to be optimized out by MSVC. */ SecureZeroMemory(ptr, len); From 8e142ca4102ade1b90dcb06d6c78405ef3220599 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Thu, 9 Mar 2023 15:29:56 +0000 Subject: [PATCH 004/100] Move `SECP256K1_INLINE` macro definition out from `include/secp256k1.h` --- include/secp256k1.h | 12 ------------ src/field_5x52_asm_impl.h | 2 ++ src/field_5x52_int128_impl.h | 1 + src/group_impl.h | 1 + src/int128_native_impl.h | 1 + src/int128_struct_impl.h | 1 + src/modules/extrakeys/main_impl.h | 1 + src/scalar_4x64_impl.h | 1 + src/scalar_8x32_impl.h | 1 + src/scalar_low_impl.h | 1 + src/testrand.h | 2 ++ src/testrand_impl.h | 1 + src/tests_exhaustive.c | 1 + src/util.h | 14 ++++++++++++++ 14 files changed, 28 insertions(+), 12 deletions(-) diff --git a/include/secp256k1.h b/include/secp256k1.h index 325f35eb04..75ffe40527 100644 --- a/include/secp256k1.h +++ b/include/secp256k1.h @@ -122,18 +122,6 @@ typedef int (*secp256k1_nonce_function)( # endif # endif -# if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) ) -# if SECP256K1_GNUC_PREREQ(2,7) -# define SECP256K1_INLINE __inline__ -# elif (defined(_MSC_VER)) -# define SECP256K1_INLINE __inline -# else -# define SECP256K1_INLINE -# endif -# else -# define SECP256K1_INLINE inline -# endif - /* When this header is used at build-time the SECP256K1_BUILD define needs to be set * to correctly setup export attributes and nullness checks. This is normally done * by secp256k1.c but to guard against this header being included before secp256k1.c diff --git a/src/field_5x52_asm_impl.h b/src/field_5x52_asm_impl.h index a2118044ab..e8efa61085 100644 --- a/src/field_5x52_asm_impl.h +++ b/src/field_5x52_asm_impl.h @@ -14,6 +14,8 @@ #ifndef SECP256K1_FIELD_INNER5X52_IMPL_H #define SECP256K1_FIELD_INNER5X52_IMPL_H +#include "util.h" + SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t *a, const uint64_t * SECP256K1_RESTRICT b) { /** * Registers: rdx:rax = multiplication accumulator diff --git a/src/field_5x52_int128_impl.h b/src/field_5x52_int128_impl.h index 18567b95f3..b2a391dec9 100644 --- a/src/field_5x52_int128_impl.h +++ b/src/field_5x52_int128_impl.h @@ -10,6 +10,7 @@ #include #include "int128.h" +#include "util.h" #ifdef VERIFY #define VERIFY_BITS(x, n) VERIFY_CHECK(((x) >> (n)) == 0) diff --git a/src/group_impl.h b/src/group_impl.h index 82ce3f8d8b..7ec069a80c 100644 --- a/src/group_impl.h +++ b/src/group_impl.h @@ -9,6 +9,7 @@ #include "field.h" #include "group.h" +#include "util.h" /* Begin of section generated by sage/gen_exhaustive_groups.sage. */ #define SECP256K1_G_ORDER_7 SECP256K1_GE_CONST(\ diff --git a/src/int128_native_impl.h b/src/int128_native_impl.h index 996e542cf9..7f02e1590b 100644 --- a/src/int128_native_impl.h +++ b/src/int128_native_impl.h @@ -2,6 +2,7 @@ #define SECP256K1_INT128_NATIVE_IMPL_H #include "int128.h" +#include "util.h" static SECP256K1_INLINE void secp256k1_u128_load(secp256k1_uint128 *r, uint64_t hi, uint64_t lo) { *r = (((uint128_t)hi) << 64) + lo; diff --git a/src/int128_struct_impl.h b/src/int128_struct_impl.h index 2eb337cb54..3073f314b0 100644 --- a/src/int128_struct_impl.h +++ b/src/int128_struct_impl.h @@ -2,6 +2,7 @@ #define SECP256K1_INT128_STRUCT_IMPL_H #include "int128.h" +#include "util.h" #if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_ARM64)) /* MSVC */ # include diff --git a/src/modules/extrakeys/main_impl.h b/src/modules/extrakeys/main_impl.h index e1003052f4..7352004457 100644 --- a/src/modules/extrakeys/main_impl.h +++ b/src/modules/extrakeys/main_impl.h @@ -9,6 +9,7 @@ #include "../../../include/secp256k1.h" #include "../../../include/secp256k1_extrakeys.h" +#include "../../util.h" static SECP256K1_INLINE int secp256k1_xonly_pubkey_load(const secp256k1_context* ctx, secp256k1_ge *ge, const secp256k1_xonly_pubkey *pubkey) { return secp256k1_pubkey_load(ctx, ge, (const secp256k1_pubkey *) pubkey); diff --git a/src/scalar_4x64_impl.h b/src/scalar_4x64_impl.h index 1b83575b3e..0809698b12 100644 --- a/src/scalar_4x64_impl.h +++ b/src/scalar_4x64_impl.h @@ -10,6 +10,7 @@ #include "checkmem.h" #include "int128.h" #include "modinv64_impl.h" +#include "util.h" /* Limbs of the secp256k1 order. */ #define SECP256K1_N_0 ((uint64_t)0xBFD25E8CD0364141ULL) diff --git a/src/scalar_8x32_impl.h b/src/scalar_8x32_impl.h index c433adce75..92f428796d 100644 --- a/src/scalar_8x32_impl.h +++ b/src/scalar_8x32_impl.h @@ -9,6 +9,7 @@ #include "checkmem.h" #include "modinv32_impl.h" +#include "util.h" /* Limbs of the secp256k1 order. */ #define SECP256K1_N_0 ((uint32_t)0xD0364141UL) diff --git a/src/scalar_low_impl.h b/src/scalar_low_impl.h index e780083339..5ce1c2d2ac 100644 --- a/src/scalar_low_impl.h +++ b/src/scalar_low_impl.h @@ -9,6 +9,7 @@ #include "checkmem.h" #include "scalar.h" +#include "util.h" #include diff --git a/src/testrand.h b/src/testrand.h index d109bb9f8b..721099d039 100644 --- a/src/testrand.h +++ b/src/testrand.h @@ -7,6 +7,8 @@ #ifndef SECP256K1_TESTRAND_H #define SECP256K1_TESTRAND_H +#include "util.h" + /* A non-cryptographic RNG used only for test infrastructure. */ /** Seed the pseudorandom number generator for testing. */ diff --git a/src/testrand_impl.h b/src/testrand_impl.h index e9b9d7ded4..1b7481a53b 100644 --- a/src/testrand_impl.h +++ b/src/testrand_impl.h @@ -13,6 +13,7 @@ #include "testrand.h" #include "hash.h" +#include "util.h" static uint64_t secp256k1_test_state[4]; static uint64_t secp256k1_test_rng_integer; diff --git a/src/tests_exhaustive.c b/src/tests_exhaustive.c index 86b9334cae..ad17d8d392 100644 --- a/src/tests_exhaustive.c +++ b/src/tests_exhaustive.c @@ -20,6 +20,7 @@ #include "testrand_impl.h" #include "ecmult_compute_table_impl.h" #include "ecmult_gen_compute_table_impl.h" +#include "util.h" static int count = 2; diff --git a/src/util.h b/src/util.h index e75c5ad552..f980f47bdc 100644 --- a/src/util.h +++ b/src/util.h @@ -7,6 +7,8 @@ #ifndef SECP256K1_UTIL_H #define SECP256K1_UTIL_H +#include "../include/secp256k1.h" + #include #include #include @@ -17,6 +19,18 @@ #define DEBUG_CONFIG_MSG(x) "DEBUG_CONFIG: " x #define DEBUG_CONFIG_DEF(x) DEBUG_CONFIG_MSG(#x "=" STR(x)) +# if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) ) +# if SECP256K1_GNUC_PREREQ(2,7) +# define SECP256K1_INLINE __inline__ +# elif (defined(_MSC_VER)) +# define SECP256K1_INLINE __inline +# else +# define SECP256K1_INLINE +# endif +# else +# define SECP256K1_INLINE inline +# endif + typedef struct { void (*fn)(const char *text, void* data); const void* data; From 36b0adf1b90139a41fdcb94390d0bb06e9224795 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Fri, 10 Mar 2023 20:21:29 +0000 Subject: [PATCH 005/100] build: remove warning until it's reproducible Also remove the interface it was attached to since it's no longer needed. This removal simplifies the next commit. --- src/CMakeLists.txt | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 26272d0950..43996cc179 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -55,11 +55,6 @@ if(SECP256K1_BUILD_STATIC) list(APPEND ${PROJECT_NAME}_installables secp256k1_static) endif() -add_library(binary_interface INTERFACE) -target_compile_definitions(binary_interface INTERFACE - $<$:_CRT_SECURE_NO_WARNINGS> -) - add_library(link_library INTERFACE) if(SECP256K1_BUILD_SHARED) target_link_libraries(link_library INTERFACE secp256k1) @@ -69,21 +64,17 @@ endif() if(SECP256K1_BUILD_BENCHMARK) add_executable(bench bench.c) - target_link_libraries(bench binary_interface link_library) + target_link_libraries(bench link_library) add_executable(bench_internal bench_internal.c ${internal_obj}) - target_link_libraries(bench_internal binary_interface) add_executable(bench_ecmult bench_ecmult.c ${internal_obj}) - target_link_libraries(bench_ecmult binary_interface) endif() if(SECP256K1_BUILD_TESTS) add_executable(noverify_tests tests.c ${internal_obj}) - target_link_libraries(noverify_tests binary_interface) add_test(noverify_tests noverify_tests) if(NOT CMAKE_BUILD_TYPE STREQUAL "Coverage") add_executable(tests tests.c ${internal_obj}) target_compile_definitions(tests PRIVATE VERIFY) - target_link_libraries(tests binary_interface) add_test(tests tests) endif() endif() @@ -92,13 +83,12 @@ if(SECP256K1_BUILD_EXHAUSTIVE_TESTS) # Note: do not include $ in exhaustive_tests (it uses runtime-generated tables). add_executable(exhaustive_tests tests_exhaustive.c ${common_obj}) target_compile_definitions(exhaustive_tests PRIVATE $<$>:VERIFY>) - target_link_libraries(exhaustive_tests binary_interface) add_test(exhaustive_tests exhaustive_tests) endif() if(SECP256K1_BUILD_CTIME_TESTS) add_executable(ctime_tests ctime_tests.c) - target_link_libraries(ctime_tests binary_interface link_library) + target_link_libraries(ctime_tests link_library) endif() install(TARGETS ${${PROJECT_NAME}_installables} From a575339c0282ba49a4f46c9c660a4cc3b6bfc703 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Thu, 29 Dec 2022 14:48:36 -0500 Subject: [PATCH 006/100] Remove bits argument from secp256k1_wnaf_const (always 256) --- src/bench_ecmult.c | 2 +- src/ecmult_const.h | 5 +-- src/ecmult_const_impl.h | 61 +++++++++++++----------------------- src/modules/ecdh/main_impl.h | 2 +- src/tests.c | 30 +++++++++--------- src/tests_exhaustive.c | 6 ++-- 6 files changed, 43 insertions(+), 63 deletions(-) diff --git a/src/bench_ecmult.c b/src/bench_ecmult.c index 98fb798d82..27d694a703 100644 --- a/src/bench_ecmult.c +++ b/src/bench_ecmult.c @@ -113,7 +113,7 @@ static void bench_ecmult_const(void* arg, int iters) { int i; for (i = 0; i < iters; ++i) { - secp256k1_ecmult_const(&data->output[i], &data->pubkeys[(data->offset1+i) % POINTS], &data->scalars[(data->offset2+i) % POINTS], 256); + secp256k1_ecmult_const(&data->output[i], &data->pubkeys[(data->offset1+i) % POINTS], &data->scalars[(data->offset2+i) % POINTS]); } } diff --git a/src/ecmult_const.h b/src/ecmult_const.h index 417f328535..9e065d555d 100644 --- a/src/ecmult_const.h +++ b/src/ecmult_const.h @@ -12,11 +12,9 @@ /** * Multiply: R = q*A (in constant-time) - * Here `bits` should be set to the maximum bitlength of the _absolute value_ of `q`, plus - * one because we internally sometimes add 2 to the number during the WNAF conversion. * A must not be infinity. */ -static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *q, int bits); +static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *q); /** * Same as secp256k1_ecmult_const, but takes in an x coordinate of the base point @@ -35,7 +33,6 @@ static int secp256k1_ecmult_const_xonly( const secp256k1_fe *n, const secp256k1_fe *d, const secp256k1_scalar *q, - int bits, int known_on_curve ); diff --git a/src/ecmult_const_impl.h b/src/ecmult_const_impl.h index f23e0ec89d..f2b6f48285 100644 --- a/src/ecmult_const_impl.h +++ b/src/ecmult_const_impl.h @@ -130,7 +130,7 @@ static int secp256k1_wnaf_const(int *wnaf, const secp256k1_scalar *scalar, int w return skew; } -static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *scalar, int size) { +static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *scalar) { secp256k1_ge pre_a[ECMULT_TABLE_SIZE(WINDOW_A)]; secp256k1_ge tmpa; secp256k1_fe Z; @@ -145,18 +145,10 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons int i; /* build wnaf representation for q. */ - int rsize = size; - if (size > 128) { - rsize = 128; - /* split q into q_1 and q_lam (where q = q_1 + q_lam*lambda, and q_1 and q_lam are ~128 bit) */ - secp256k1_scalar_split_lambda(&q_1, &q_lam, scalar); - skew_1 = secp256k1_wnaf_const(wnaf_1, &q_1, WINDOW_A - 1, 128); - skew_lam = secp256k1_wnaf_const(wnaf_lam, &q_lam, WINDOW_A - 1, 128); - } else - { - skew_1 = secp256k1_wnaf_const(wnaf_1, scalar, WINDOW_A - 1, size); - skew_lam = 0; - } + /* split q into q_1 and q_lam (where q = q_1 + q_lam*lambda, and q_1 and q_lam are ~128 bit) */ + secp256k1_scalar_split_lambda(&q_1, &q_lam, scalar); + skew_1 = secp256k1_wnaf_const(wnaf_1, &q_1, WINDOW_A - 1, 128); + skew_lam = secp256k1_wnaf_const(wnaf_lam, &q_lam, WINDOW_A - 1, 128); /* Calculate odd multiples of a. * All multiples are brought to the same Z 'denominator', which is stored @@ -170,28 +162,23 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) { secp256k1_fe_normalize_weak(&pre_a[i].y); } - if (size > 128) { - for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) { - secp256k1_ge_mul_lambda(&pre_a_lam[i], &pre_a[i]); - } - + for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) { + secp256k1_ge_mul_lambda(&pre_a_lam[i], &pre_a[i]); } /* first loop iteration (separated out so we can directly set r, rather * than having it start at infinity, get doubled several times, then have * its new value added to it) */ - i = wnaf_1[WNAF_SIZE_BITS(rsize, WINDOW_A - 1)]; + i = wnaf_1[WNAF_SIZE_BITS(128, WINDOW_A - 1)]; VERIFY_CHECK(i != 0); ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, i, WINDOW_A); secp256k1_gej_set_ge(r, &tmpa); - if (size > 128) { - i = wnaf_lam[WNAF_SIZE_BITS(rsize, WINDOW_A - 1)]; - VERIFY_CHECK(i != 0); - ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, i, WINDOW_A); - secp256k1_gej_add_ge(r, r, &tmpa); - } + i = wnaf_lam[WNAF_SIZE_BITS(128, WINDOW_A - 1)]; + VERIFY_CHECK(i != 0); + ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, i, WINDOW_A); + secp256k1_gej_add_ge(r, r, &tmpa); /* remaining loop iterations */ - for (i = WNAF_SIZE_BITS(rsize, WINDOW_A - 1) - 1; i >= 0; i--) { + for (i = WNAF_SIZE_BITS(128, WINDOW_A - 1) - 1; i >= 0; i--) { int n; int j; for (j = 0; j < WINDOW_A - 1; ++j) { @@ -202,12 +189,10 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, n, WINDOW_A); VERIFY_CHECK(n != 0); secp256k1_gej_add_ge(r, r, &tmpa); - if (size > 128) { - n = wnaf_lam[i]; - ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, n, WINDOW_A); - VERIFY_CHECK(n != 0); - secp256k1_gej_add_ge(r, r, &tmpa); - } + n = wnaf_lam[i]; + ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, n, WINDOW_A); + VERIFY_CHECK(n != 0); + secp256k1_gej_add_ge(r, r, &tmpa); } { @@ -218,17 +203,15 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons secp256k1_gej_add_ge(&tmpj, r, &tmpa); secp256k1_gej_cmov(r, &tmpj, skew_1); - if (size > 128) { - secp256k1_ge_neg(&tmpa, &pre_a_lam[0]); - secp256k1_gej_add_ge(&tmpj, r, &tmpa); - secp256k1_gej_cmov(r, &tmpj, skew_lam); - } + secp256k1_ge_neg(&tmpa, &pre_a_lam[0]); + secp256k1_gej_add_ge(&tmpj, r, &tmpa); + secp256k1_gej_cmov(r, &tmpj, skew_lam); } secp256k1_fe_mul(&r->z, &r->z, &Z); } -static int secp256k1_ecmult_const_xonly(secp256k1_fe* r, const secp256k1_fe *n, const secp256k1_fe *d, const secp256k1_scalar *q, int bits, int known_on_curve) { +static int secp256k1_ecmult_const_xonly(secp256k1_fe* r, const secp256k1_fe *n, const secp256k1_fe *d, const secp256k1_scalar *q, int known_on_curve) { /* This algorithm is a generalization of Peter Dettman's technique for * avoiding the square root in a random-basepoint x-only multiplication @@ -346,7 +329,7 @@ static int secp256k1_ecmult_const_xonly(secp256k1_fe* r, const secp256k1_fe *n, #ifdef VERIFY VERIFY_CHECK(!secp256k1_scalar_is_zero(q)); #endif - secp256k1_ecmult_const(&rj, &p, q, bits); + secp256k1_ecmult_const(&rj, &p, q); #ifdef VERIFY VERIFY_CHECK(!secp256k1_gej_is_infinity(&rj)); #endif diff --git a/src/modules/ecdh/main_impl.h b/src/modules/ecdh/main_impl.h index 5408c9de70..82b082a9f0 100644 --- a/src/modules/ecdh/main_impl.h +++ b/src/modules/ecdh/main_impl.h @@ -50,7 +50,7 @@ int secp256k1_ecdh(const secp256k1_context* ctx, unsigned char *output, const se overflow |= secp256k1_scalar_is_zero(&s); secp256k1_scalar_cmov(&s, &secp256k1_scalar_one, overflow); - secp256k1_ecmult_const(&res, &pt, &s, 256); + secp256k1_ecmult_const(&res, &pt, &s); secp256k1_ge_set_gej(&pt, &res); /* Compute a hash of the point */ diff --git a/src/tests.c b/src/tests.c index 729b7f852e..a9201b74b3 100644 --- a/src/tests.c +++ b/src/tests.c @@ -4338,9 +4338,9 @@ static void test_ecmult_target(const secp256k1_scalar* target, int mode) { secp256k1_ecmult(&p2j, &pj, &n2, &zero); secp256k1_ecmult(&ptj, &pj, target, &zero); } else { - secp256k1_ecmult_const(&p1j, &p, &n1, 256); - secp256k1_ecmult_const(&p2j, &p, &n2, 256); - secp256k1_ecmult_const(&ptj, &p, target, 256); + secp256k1_ecmult_const(&p1j, &p, &n1); + secp256k1_ecmult_const(&p2j, &p, &n2); + secp256k1_ecmult_const(&ptj, &p, target); } /* Add them all up: n1*P + n2*P + target*P = (n1+n2+target)*P = (n1+n1-n1-n2)*P = 0. */ @@ -4403,7 +4403,7 @@ static void ecmult_const_random_mult(void) { 0xb84e4e1b, 0xfb77e21f, 0x96baae2a, 0x63dec956 ); secp256k1_gej b; - secp256k1_ecmult_const(&b, &a, &xn, 256); + secp256k1_ecmult_const(&b, &a, &xn); CHECK(secp256k1_ge_is_valid_var(&a)); ge_equals_gej(&expected_b, &b); @@ -4419,12 +4419,12 @@ static void ecmult_const_commutativity(void) { random_scalar_order_test(&a); random_scalar_order_test(&b); - secp256k1_ecmult_const(&res1, &secp256k1_ge_const_g, &a, 256); - secp256k1_ecmult_const(&res2, &secp256k1_ge_const_g, &b, 256); + secp256k1_ecmult_const(&res1, &secp256k1_ge_const_g, &a); + secp256k1_ecmult_const(&res2, &secp256k1_ge_const_g, &b); secp256k1_ge_set_gej(&mid1, &res1); secp256k1_ge_set_gej(&mid2, &res2); - secp256k1_ecmult_const(&res1, &mid1, &b, 256); - secp256k1_ecmult_const(&res2, &mid2, &a, 256); + secp256k1_ecmult_const(&res1, &mid1, &b); + secp256k1_ecmult_const(&res2, &mid2, &a); secp256k1_ge_set_gej(&mid1, &res1); secp256k1_ge_set_gej(&mid2, &res2); ge_equals_ge(&mid1, &mid2); @@ -4440,13 +4440,13 @@ static void ecmult_const_mult_zero_one(void) { secp256k1_scalar_negate(&negone, &one); random_group_element_test(&point); - secp256k1_ecmult_const(&res1, &point, &zero, 3); + secp256k1_ecmult_const(&res1, &point, &zero); secp256k1_ge_set_gej(&res2, &res1); CHECK(secp256k1_ge_is_infinity(&res2)); - secp256k1_ecmult_const(&res1, &point, &one, 2); + secp256k1_ecmult_const(&res1, &point, &one); secp256k1_ge_set_gej(&res2, &res1); ge_equals_ge(&res2, &point); - secp256k1_ecmult_const(&res1, &point, &negone, 256); + secp256k1_ecmult_const(&res1, &point, &negone); secp256k1_gej_neg(&res1, &res1); secp256k1_ge_set_gej(&res2, &res1); ge_equals_ge(&res2, &point); @@ -4476,7 +4476,7 @@ static void ecmult_const_mult_xonly(void) { n = base.x; } /* Perform x-only multiplication. */ - res = secp256k1_ecmult_const_xonly(&resx, &n, (i & 1) ? &d : NULL, &q, 256, i & 2); + res = secp256k1_ecmult_const_xonly(&resx, &n, (i & 1) ? &d : NULL, &q, i & 2); CHECK(res); /* Perform normal multiplication. */ secp256k1_gej_set_ge(&basej, &base); @@ -4509,7 +4509,7 @@ static void ecmult_const_mult_xonly(void) { } else { n = x; } - res = secp256k1_ecmult_const_xonly(&r, &n, (i & 1) ? &d : NULL, &q, 256, 0); + res = secp256k1_ecmult_const_xonly(&r, &n, (i & 1) ? &d : NULL, &q, 0); CHECK(res == 0); } } @@ -4534,7 +4534,7 @@ static void ecmult_const_chain_multiply(void) { for (i = 0; i < 100; ++i) { secp256k1_ge tmp; secp256k1_ge_set_gej(&tmp, &point); - secp256k1_ecmult_const(&point, &tmp, &scalar, 256); + secp256k1_ecmult_const(&point, &tmp, &scalar); } secp256k1_ge_set_gej(&res, &point); ge_equals_gej(&res, &expected_point); @@ -5432,7 +5432,7 @@ static void test_ecmult_accumulate(secp256k1_sha256* acc, const secp256k1_scalar secp256k1_ecmult(&rj3, &infj, &zero, x); secp256k1_ecmult_multi_var(NULL, scratch, &rj4, x, NULL, NULL, 0); secp256k1_ecmult_multi_var(NULL, scratch, &rj5, &zero, test_ecmult_accumulate_cb, (void*)x, 1); - secp256k1_ecmult_const(&rj6, &secp256k1_ge_const_g, x, 256); + secp256k1_ecmult_const(&rj6, &secp256k1_ge_const_g, x); secp256k1_ge_set_gej_var(&r, &rj1); ge_equals_gej(&r, &rj2); ge_equals_gej(&r, &rj3); diff --git a/src/tests_exhaustive.c b/src/tests_exhaustive.c index 63b6ef03af..e7bd6c724a 100644 --- a/src/tests_exhaustive.c +++ b/src/tests_exhaustive.c @@ -203,19 +203,19 @@ static void test_exhaustive_ecmult(const secp256k1_ge *group, const secp256k1_ge secp256k1_scalar_set_int(&ng, j); /* Test secp256k1_ecmult_const. */ - secp256k1_ecmult_const(&tmp, &group[i], &ng, 256); + secp256k1_ecmult_const(&tmp, &group[i], &ng); ge_equals_gej(&group[(i * j) % EXHAUSTIVE_TEST_ORDER], &tmp); if (j != 0) { /* Test secp256k1_ecmult_const_xonly with all curve X coordinates, and xd=NULL. */ - ret = secp256k1_ecmult_const_xonly(&tmpf, &group[i].x, NULL, &ng, 256, 0); + ret = secp256k1_ecmult_const_xonly(&tmpf, &group[i].x, NULL, &ng, 0); CHECK(ret); CHECK(secp256k1_fe_equal_var(&tmpf, &group[(i * j) % EXHAUSTIVE_TEST_ORDER].x)); /* Test secp256k1_ecmult_const_xonly with all curve X coordinates, with random xd. */ random_fe_non_zero(&xd); secp256k1_fe_mul(&xn, &xd, &group[i].x); - ret = secp256k1_ecmult_const_xonly(&tmpf, &xn, &xd, &ng, 256, 0); + ret = secp256k1_ecmult_const_xonly(&tmpf, &xn, &xd, &ng, 0); CHECK(ret); CHECK(secp256k1_fe_equal_var(&tmpf, &group[(i * j) % EXHAUSTIVE_TEST_ORDER].x)); } From 1b6fb5593c3b0dad8f8ad17ddd29ca30ebd00af3 Mon Sep 17 00:00:00 2001 From: Jonas Nick Date: Mon, 10 Apr 2023 15:19:07 +0000 Subject: [PATCH 007/100] doc: clarify process for patch releases --- doc/release-process.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/doc/release-process.md b/doc/release-process.md index 70a35f0910..79dc36ecc3 100644 --- a/doc/release-process.md +++ b/doc/release-process.md @@ -16,8 +16,10 @@ This process also assumes that there will be no minor releases for old major rel 1. Open a PR to the master branch with a commit (using message `"release: prepare for $MAJOR.$MINOR.$PATCH"`, for example) that * finalizes the release notes in [CHANGELOG.md](../CHANGELOG.md) (make sure to include an entry for `### ABI Compatibility`), - * updates `_PKG_VERSION_*` and `_LIB_VERSION_*` and sets `_PKG_VERSION_IS_RELEASE` to `true` in `configure.ac`, and - * updates `project(libsecp256k1 VERSION ...)` and `${PROJECT_NAME}_LIB_VERSION_*` in `CMakeLists.txt`. + * sets `_PKG_VERSION_IS_RELEASE` to `true` in `configure.ac`, and + * if this is not a patch release + * updates `_PKG_VERSION_*` and `_LIB_VERSION_*` in `configure.ac` and + * updates `project(libsecp256k1 VERSION ...)` and `${PROJECT_NAME}_LIB_VERSION_*` in `CMakeLists.txt`. 2. After the PR is merged, tag the commit and push it: ``` RELEASE_COMMIT= From 1ecb94ebe9800900c7dd3a4f9883c600e25eecf7 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Tue, 11 Apr 2023 18:59:12 +0100 Subject: [PATCH 008/100] build: Make `SECP_VALGRIND_CHECK` preserve `CPPFLAGS` --- build-aux/m4/bitcoin_secp.m4 | 1 + 1 file changed, 1 insertion(+) diff --git a/build-aux/m4/bitcoin_secp.m4 b/build-aux/m4/bitcoin_secp.m4 index 624f5e956e..154157ffb4 100644 --- a/build-aux/m4/bitcoin_secp.m4 +++ b/build-aux/m4/bitcoin_secp.m4 @@ -21,6 +21,7 @@ if test x"$has_valgrind" != x"yes"; then # error "Valgrind does not support this platform." #endif ]])], [has_valgrind=yes]) + CPPFLAGS="$CPPFLAGS_TEMP" fi AC_MSG_RESULT($has_valgrind) ]) From dc0657c7622f5a13afc3876eca7e2fc7cabb9a10 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Thu, 13 Apr 2023 12:23:30 +0100 Subject: [PATCH 009/100] build: Fix C4005 "macro redefinition" MSVC warnings in examples --- configure.ac | 1 - examples/CMakeLists.txt | 3 --- examples/examples_util.h | 6 ++++++ 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index 0b555eac67..6bf5b573dd 100644 --- a/configure.ac +++ b/configure.ac @@ -122,7 +122,6 @@ AC_DEFUN([SECP_TRY_APPEND_DEFAULT_CFLAGS], [ # Note that "/opt" and "-opt" are equivalent for MSVC; we use "-opt" because "/opt" looks like a path. if test x"$GCC" != x"yes" && test x"$build_windows" = x"yes"; then SECP_TRY_APPEND_CFLAGS([-W2 -wd4146], $1) # Moderate warning level, disable warning C4146 "unary minus operator applied to unsigned type, result still unsigned" - SECP_TRY_APPEND_CFLAGS([-external:anglebrackets -external:W0], $1) # Suppress warnings from #include <...> files # We pass -ignore:4217 to the MSVC linker to suppress warning 4217 when # importing variables from a statically linked secp256k1. # (See the libtool manual, section "Windows DLLs" for background.) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 0884b645e0..f60cde4377 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -2,9 +2,6 @@ add_library(example INTERFACE) target_include_directories(example INTERFACE ${PROJECT_SOURCE_DIR}/include ) -target_compile_options(example INTERFACE - $<$:/wd4005> -) target_link_libraries(example INTERFACE $<$:bcrypt> ) diff --git a/examples/examples_util.h b/examples/examples_util.h index a52b1fa115..507cd5594c 100644 --- a/examples/examples_util.h +++ b/examples/examples_util.h @@ -17,7 +17,13 @@ */ #if defined(_WIN32) +/* + * The defined WIN32_NO_STATUS macro disables return code definitions in + * windows.h, which avoids "macro redefinition" MSVC warnings in ntstatus.h. + */ +#define WIN32_NO_STATUS #include +#undef WIN32_NO_STATUS #include #include #elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) From 529b54d9224e680197e6052b505d2a66398e0d36 Mon Sep 17 00:00:00 2001 From: Tim Ruffing Date: Fri, 14 Apr 2023 07:11:46 +0200 Subject: [PATCH 010/100] autotools: Move Wycheproof header from EXTRA_DIST to noinst_HEADERS --- Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index 36e26e3e8a..23555e344f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -65,6 +65,7 @@ noinst_HEADERS += src/hash_impl.h noinst_HEADERS += src/field.h noinst_HEADERS += src/field_impl.h noinst_HEADERS += src/bench.h +noinst_HEADERS += src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.h noinst_HEADERS += contrib/lax_der_parsing.h noinst_HEADERS += contrib/lax_der_parsing.c noinst_HEADERS += contrib/lax_der_privatekey_parsing.h @@ -249,7 +250,6 @@ include src/modules/schnorrsig/Makefile.am.include endif EXTRA_DIST += src/wycheproof/WYCHEPROOF_COPYING -EXTRA_DIST += src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.h EXTRA_DIST += src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.json EXTRA_DIST += tools/tests_wycheproof_generate.py From 35ada3b954ccc6c54628fb3bcc0365d176297019 Mon Sep 17 00:00:00 2001 From: RandomLattice <128569685+RandomLattice@users.noreply.github.com> Date: Fri, 14 Apr 2023 13:30:51 +0200 Subject: [PATCH 011/100] tests: lint wycheproof's python script This PR lints tests_wycheproof_generate.py according to pylint. This is a follow-up to PR #1245. Co-authored-by: Sean Andersen <6730974+andozw@users.noreply.github.com> --- tools/tests_wycheproof_generate.py | 43 +++++++++++++++--------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/tools/tests_wycheproof_generate.py b/tools/tests_wycheproof_generate.py index 333f6fbef0..b26dfa89d6 100755 --- a/tools/tests_wycheproof_generate.py +++ b/tools/tests_wycheproof_generate.py @@ -7,8 +7,6 @@ ''' import json -import hashlib -import urllib.request import sys filename_input = sys.argv[1] @@ -19,7 +17,8 @@ num_groups = len(doc['testGroups']) def to_c_array(x): - if x == "": return "" + if x == "": + return "" s = ',0x'.join(a+b for a,b in zip(x[::2], x[1::2])) return "0x" + s @@ -43,18 +42,23 @@ def to_c_array(x): sig_size = len(test_vector['sig']) // 2 msg_size = len(test_vector['msg']) // 2 - if test_vector['result'] == "invalid": expected_verify = 0 - elif test_vector['result'] == "valid": expected_verify = 1 - else: raise ValueError("invalid result field") + if test_vector['result'] == "invalid": + expected_verify = 0 + elif test_vector['result'] == "valid": + expected_verify = 1 + else: + raise ValueError("invalid result field") - if num_vectors != 0 and sig_size != 0: signatures += ",\n " + if num_vectors != 0 and sig_size != 0: + signatures += ",\n " new_msg = False msg = to_c_array(test_vector['msg']) msg_offset = offset_msg_running # check for repeated msg - if msg not in cache_msgs.keys(): - if num_vectors != 0 and msg_size != 0: messages += ",\n " + if msg not in cache_msgs: + if num_vectors != 0 and msg_size != 0: + messages += ",\n " cache_msgs[msg] = offset_msg_running messages += msg new_msg = True @@ -65,8 +69,9 @@ def to_c_array(x): pk = to_c_array(public_key['uncompressed']) pk_offset = offset_pk_running # check for repeated pk - if pk not in cache_public_keys.keys(): - if num_vectors != 0: public_keys += ",\n " + if pk not in cache_public_keys: + if num_vectors != 0: + public_keys += ",\n " cache_public_keys[pk] = offset_pk_running public_keys += pk new_pk = True @@ -76,15 +81,11 @@ def to_c_array(x): signatures += to_c_array(test_vector['sig']) out += " /" + "* tcId: " + str(test_vector['tcId']) + ". " + test_vector['comment'] + " *" + "/\n" - out += " {" + "{0}, {1}, {2}, {3}, {4}, {5}".format( - pk_offset, - msg_offset, - msg_size, - offset_sig, - sig_size, - expected_verify) + " },\n" - if new_msg: offset_msg_running += msg_size - if new_pk: offset_pk_running += 65 + out += f" {{{pk_offset}, {msg_offset}, {msg_size}, {offset_sig}, {sig_size}, {expected_verify} }},\n" + if new_msg: + offset_msg_running += msg_size + if new_pk: + offset_pk_running += 65 offset_sig += sig_size num_vectors += 1 @@ -101,7 +102,7 @@ def to_c_array(x): print("/* Note: this file was autogenerated using tests_wycheproof_generate.py. Do not edit. */") -print("#define SECP256K1_ECDSA_WYCHEPROOF_NUMBER_TESTVECTORS ({})".format(num_vectors)) +print(f"#define SECP256K1_ECDSA_WYCHEPROOF_NUMBER_TESTVECTORS ({num_vectors})") print(struct_definition) From ef49a11d29601e09e94134975c968e92c0214102 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Tue, 14 Mar 2023 21:15:35 +0000 Subject: [PATCH 012/100] build: allow static or shared but not both --- CMakeLists.txt | 18 +++++--- examples/CMakeLists.txt | 10 ++--- src/CMakeLists.txt | 96 +++++++++++++++++------------------------ 3 files changed, 53 insertions(+), 71 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2ddf91aed0..40e88e3648 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,11 +26,10 @@ set(CMAKE_C_EXTENSIONS OFF) list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake) -# We do not use CMake's BUILD_SHARED_LIBS option. -option(SECP256K1_BUILD_SHARED "Build shared library." ON) -option(SECP256K1_BUILD_STATIC "Build static library." ON) -if(NOT SECP256K1_BUILD_SHARED AND NOT SECP256K1_BUILD_STATIC) - message(FATAL_ERROR "At least one of SECP256K1_BUILD_SHARED and SECP256K1_BUILD_STATIC must be enabled.") +option(BUILD_SHARED_LIBS "Build shared libraries" ON) +option(SECP256K1_DISABLE_SHARED "Disable shared library. Overrides BUILD_SHARED_LIBS." OFF) +if(SECP256K1_DISABLE_SHARED) + set(BUILD_SHARED_LIBS OFF) endif() option(SECP256K1_ENABLE_MODULE_ECDH "Enable ECDH module." ON) @@ -225,8 +224,13 @@ message("\n") message("secp256k1 configure summary") message("===========================") message("Build artifacts:") -message(" shared library ...................... ${SECP256K1_BUILD_SHARED}") -message(" static library ...................... ${SECP256K1_BUILD_STATIC}") +if(BUILD_SHARED_LIBS) + set(library_type "Shared") +else() + set(library_type "Static") +endif() + +message(" library type ........................ ${library_type}") message("Optional modules:") message(" ECDH ................................ ${SECP256K1_ENABLE_MODULE_ECDH}") message(" ECDSA pubkey recovery ............... ${SECP256K1_ENABLE_MODULE_RECOVERY}") diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 0884b645e0..ba2fe122f1 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -6,15 +6,11 @@ target_compile_options(example INTERFACE $<$:/wd4005> ) target_link_libraries(example INTERFACE + secp256k1 $<$:bcrypt> ) -if(SECP256K1_BUILD_SHARED) - target_link_libraries(example INTERFACE secp256k1) -elseif(SECP256K1_BUILD_STATIC) - target_link_libraries(example INTERFACE secp256k1_static) - if(MSVC) - target_link_options(example INTERFACE /IGNORE:4217) - endif() +if(NOT BUILD_SHARED_LIBS AND MSVC) + target_link_options(example INTERFACE /IGNORE:4217) endif() add_executable(ecdsa_example ecdsa.c) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 43996cc179..4758fad1c2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,97 +1,79 @@ # Must be included before CMAKE_INSTALL_INCLUDEDIR is used. include(GNUInstallDirs) -set(${PROJECT_NAME}_installables "") +add_library(secp256k1_precomputed OBJECT EXCLUDE_FROM_ALL + precomputed_ecmult.c + precomputed_ecmult_gen.c +) + +# Add objects explicitly rather than linking to the object libs to keep them +# from being exported. +add_library(secp256k1 secp256k1.c $) + +add_library(secp256k1_asm INTERFACE) if(SECP256K1_ASM STREQUAL "arm") - add_library(common OBJECT + add_library(secp256k1_asm_arm OBJECT EXCLUDE_FROM_ALL) + target_sources(secp256k1_asm_arm PUBLIC asm/field_10x26_arm.s ) - set(common_obj "$") -else() - set(common_obj "") + target_sources(secp256k1 PRIVATE $) + target_link_libraries(secp256k1_asm INTERFACE secp256k1_asm_arm) endif() -add_library(precomputed OBJECT - precomputed_ecmult.c - precomputed_ecmult_gen.c -) -set(internal_obj "$" "${common_obj}") +# Define our export symbol only for Win32 and only for shared libs. +# This matches libtool's usage of DLL_EXPORT +if(WIN32) + set_target_properties(secp256k1 PROPERTIES DEFINE_SYMBOL "DLL_EXPORT") +endif() -add_library(secp256k1 SHARED EXCLUDE_FROM_ALL - secp256k1.c - ${internal_obj} -) -target_include_directories(secp256k1 INTERFACE +# Object libs don't know if they're being built for a shared or static lib. +# Grab the PIC property from secp256k1 which knows. +get_target_property(use_pic secp256k1 POSITION_INDEPENDENT_CODE) +set_target_properties(secp256k1_precomputed PROPERTIES POSITION_INDEPENDENT_CODE ${use_pic}) + +target_include_directories(secp256k1 PUBLIC $ ) -target_compile_definitions(secp256k1 PRIVATE - $<$:DLL_EXPORT> -) set_target_properties(secp256k1 PROPERTIES VERSION "${${PROJECT_NAME}_LIB_VERSION_CURRENT}.${${PROJECT_NAME}_LIB_VERSION_AGE}.${${PROJECT_NAME}_LIB_VERSION_REVISION}" SOVERSION "${${PROJECT_NAME}_LIB_VERSION_CURRENT}" ) -if(SECP256K1_BUILD_SHARED) - get_target_property(use_pic secp256k1 POSITION_INDEPENDENT_CODE) - set_target_properties(precomputed PROPERTIES POSITION_INDEPENDENT_CODE ${use_pic}) - set_target_properties(secp256k1 PROPERTIES EXCLUDE_FROM_ALL FALSE) - list(APPEND ${PROJECT_NAME}_installables secp256k1) -endif() - -add_library(secp256k1_static STATIC EXCLUDE_FROM_ALL - secp256k1.c - ${internal_obj} -) -target_include_directories(secp256k1_static INTERFACE - $ -) -if(NOT MSVC) - set_target_properties(secp256k1_static PROPERTIES - OUTPUT_NAME secp256k1 - ) -endif() -if(SECP256K1_BUILD_STATIC) - set_target_properties(secp256k1_static PROPERTIES EXCLUDE_FROM_ALL FALSE) - list(APPEND ${PROJECT_NAME}_installables secp256k1_static) -endif() - -add_library(link_library INTERFACE) -if(SECP256K1_BUILD_SHARED) - target_link_libraries(link_library INTERFACE secp256k1) -elseif(SECP256K1_BUILD_STATIC) - target_link_libraries(link_library INTERFACE secp256k1_static) -endif() if(SECP256K1_BUILD_BENCHMARK) add_executable(bench bench.c) - target_link_libraries(bench link_library) - add_executable(bench_internal bench_internal.c ${internal_obj}) - add_executable(bench_ecmult bench_ecmult.c ${internal_obj}) + target_link_libraries(bench secp256k1) + add_executable(bench_internal bench_internal.c) + target_link_libraries(bench_internal secp256k1_precomputed secp256k1_asm) + add_executable(bench_ecmult bench_ecmult.c) + target_link_libraries(bench_ecmult secp256k1_precomputed secp256k1_asm) endif() if(SECP256K1_BUILD_TESTS) - add_executable(noverify_tests tests.c ${internal_obj}) + add_executable(noverify_tests tests.c) + target_link_libraries(noverify_tests secp256k1_precomputed secp256k1_asm) add_test(noverify_tests noverify_tests) if(NOT CMAKE_BUILD_TYPE STREQUAL "Coverage") - add_executable(tests tests.c ${internal_obj}) + add_executable(tests tests.c) target_compile_definitions(tests PRIVATE VERIFY) + target_link_libraries(tests secp256k1_precomputed secp256k1_asm) add_test(tests tests) endif() endif() if(SECP256K1_BUILD_EXHAUSTIVE_TESTS) - # Note: do not include $ in exhaustive_tests (it uses runtime-generated tables). - add_executable(exhaustive_tests tests_exhaustive.c ${common_obj}) + # Note: do not include secp256k1_precomputed in exhaustive_tests (it uses runtime-generated tables). + add_executable(exhaustive_tests tests_exhaustive.c) + target_link_libraries(exhaustive_tests secp256k1_asm) target_compile_definitions(exhaustive_tests PRIVATE $<$>:VERIFY>) add_test(exhaustive_tests exhaustive_tests) endif() if(SECP256K1_BUILD_CTIME_TESTS) add_executable(ctime_tests ctime_tests.c) - target_link_libraries(ctime_tests link_library) + target_link_libraries(ctime_tests secp256k1) endif() -install(TARGETS ${${PROJECT_NAME}_installables} +install(TARGETS secp256k1 EXPORT ${PROJECT_NAME}-targets RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} From 08f4b1632d0ad976fe00ee606f3a95894555a2e1 Mon Sep 17 00:00:00 2001 From: Tim Ruffing Date: Fri, 14 Apr 2023 07:22:01 +0200 Subject: [PATCH 013/100] autotools: Move code around to tidy Makefile --- Makefile.am | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/Makefile.am b/Makefile.am index 23555e344f..20024e474e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -223,6 +223,20 @@ maintainer-clean-local: clean-precomp clean-precomp: rm -f $(PRECOMP) +### Pregenerated test vectors +TESTVECTORS = src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.h + +src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.h: + python3 tools/tests_wycheproof_generate.py src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.json > $@ + +testvectors: $(TESTVECTORS) + +maintainer-clean-testvectors: clean-testvectors + +clean-testvectors: + rm -f $(TESTVECTORS) + +### Additional files to distribute EXTRA_DIST = autogen.sh CHANGELOG.md SECURITY.md EXTRA_DIST += doc/release-process.md doc/safegcd_implementation.md EXTRA_DIST += examples/EXAMPLES_COPYING @@ -232,6 +246,9 @@ EXTRA_DIST += sage/group_prover.sage EXTRA_DIST += sage/prove_group_implementations.sage EXTRA_DIST += sage/secp256k1_params.sage EXTRA_DIST += sage/weierstrass_prover.sage +EXTRA_DIST += src/wycheproof/WYCHEPROOF_COPYING +EXTRA_DIST += src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.json +EXTRA_DIST += tools/tests_wycheproof_generate.py if ENABLE_MODULE_ECDH include src/modules/ecdh/Makefile.am.include @@ -248,19 +265,3 @@ endif if ENABLE_MODULE_SCHNORRSIG include src/modules/schnorrsig/Makefile.am.include endif - -EXTRA_DIST += src/wycheproof/WYCHEPROOF_COPYING -EXTRA_DIST += src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.json -EXTRA_DIST += tools/tests_wycheproof_generate.py - -TESTVECTORS = src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.h - -src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.h: - python3 tools/tests_wycheproof_generate.py src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.json > $@ - -testvectors: $(TESTVECTORS) - -maintainer-clean-testvectors: clean-testvectors - -clean-testvectors: - rm -f $(TESTVECTORS) From 47ac3d63cd5e00a2d50cb489461c8bc349d37912 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anna=20=E2=80=9CCyberTailor=E2=80=9D?= Date: Sun, 9 Apr 2023 12:51:53 +0500 Subject: [PATCH 014/100] cmake: Make installation optional Useful for embedding secp256k1 in a subproject. --- CMakeLists.txt | 2 + src/CMakeLists.txt | 93 ++++++++++++++++++++++++---------------------- 2 files changed, 50 insertions(+), 45 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cbc35fa8af..91d2bed02c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,6 +32,8 @@ if(SECP256K1_DISABLE_SHARED) set(BUILD_SHARED_LIBS OFF) endif() +option(SECP256K1_INSTALL "Enable installation" ON) + option(SECP256K1_ENABLE_MODULE_ECDH "Enable ECDH module." ON) if(SECP256K1_ENABLE_MODULE_ECDH) add_definitions(-DENABLE_MODULE_ECDH=1) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4758fad1c2..cd1d6f00ee 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -73,51 +73,54 @@ if(SECP256K1_BUILD_CTIME_TESTS) target_link_libraries(ctime_tests secp256k1) endif() -install(TARGETS secp256k1 - EXPORT ${PROJECT_NAME}-targets - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} -) -set(${PROJECT_NAME}_headers - "${PROJECT_SOURCE_DIR}/include/secp256k1.h" - "${PROJECT_SOURCE_DIR}/include/secp256k1_preallocated.h" -) -if(SECP256K1_ENABLE_MODULE_ECDH) - list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_ecdh.h") -endif() -if(SECP256K1_ENABLE_MODULE_RECOVERY) - list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_recovery.h") -endif() -if(SECP256K1_ENABLE_MODULE_EXTRAKEYS) - list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_extrakeys.h") -endif() -if(SECP256K1_ENABLE_MODULE_SCHNORRSIG) - list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_schnorrsig.h") -endif() -install(FILES ${${PROJECT_NAME}_headers} - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} -) +if(SECP256K1_INSTALL) + install(TARGETS secp256k1 + EXPORT ${PROJECT_NAME}-targets + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + ) + set(${PROJECT_NAME}_headers + "${PROJECT_SOURCE_DIR}/include/secp256k1.h" + "${PROJECT_SOURCE_DIR}/include/secp256k1_preallocated.h" + ) + if(SECP256K1_ENABLE_MODULE_ECDH) + list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_ecdh.h") + endif() + if(SECP256K1_ENABLE_MODULE_RECOVERY) + list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_recovery.h") + endif() + if(SECP256K1_ENABLE_MODULE_EXTRAKEYS) + list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_extrakeys.h") + endif() + if(SECP256K1_ENABLE_MODULE_SCHNORRSIG) + list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_schnorrsig.h") + endif() + install(FILES ${${PROJECT_NAME}_headers} + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + ) -install(EXPORT ${PROJECT_NAME}-targets - FILE ${PROJECT_NAME}-targets.cmake - NAMESPACE ${PROJECT_NAME}:: - DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME} -) + install(EXPORT ${PROJECT_NAME}-targets + FILE ${PROJECT_NAME}-targets.cmake + NAMESPACE ${PROJECT_NAME}:: + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME} + ) -include(CMakePackageConfigHelpers) -configure_package_config_file( - ${PROJECT_SOURCE_DIR}/cmake/config.cmake.in - ${PROJECT_NAME}-config.cmake - INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME} - NO_SET_AND_CHECK_MACRO -) -write_basic_package_version_file(${PROJECT_NAME}-config-version.cmake - COMPATIBILITY SameMajorVersion -) -install( - FILES - ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake - ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake - DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME} + include(CMakePackageConfigHelpers) + configure_package_config_file( + ${PROJECT_SOURCE_DIR}/cmake/config.cmake.in + ${PROJECT_NAME}-config.cmake + INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME} + NO_SET_AND_CHECK_MACRO + ) + write_basic_package_version_file(${PROJECT_NAME}-config-version.cmake + COMPATIBILITY SameMajorVersion + ) + + install( + FILES + ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake + ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME} ) +endif() From 8a8b6536ef52fbbd9690f859d2f02d7f4b3789f6 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Sun, 12 Mar 2023 19:45:00 +0000 Subject: [PATCH 015/100] cmake: Use `SameMinorVersion` compatibility mode Available in CMake 3.11+. --- src/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index cd1d6f00ee..24eb0d3011 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -114,7 +114,7 @@ if(SECP256K1_INSTALL) NO_SET_AND_CHECK_MACRO ) write_basic_package_version_file(${PROJECT_NAME}-config-version.cmake - COMPATIBILITY SameMajorVersion + COMPATIBILITY SameMinorVersion ) install( From 04d4cc071a7aa92ad5edcf970a6cc2a8f415d36c Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Sun, 26 Mar 2023 13:00:14 +0100 Subject: [PATCH 016/100] cmake: Add `DESCRIPTION` and `HOMEPAGE_URL` options to `project` command `DESCRIPTION` is available in CMake 3.9+. `HOMEPAGE_URL` is available in CMake 3.12+. --- CMakeLists.txt | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 91d2bed02c..92ecf31759 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,10 +7,15 @@ if(CMAKE_VERSION VERSION_GREATER 3.14) cmake_policy(SET CMP0092 NEW) endif() -# The package (a.k.a. release) version is based on semantic versioning 2.0.0 of -# the API. All changes in experimental modules are treated as -# backwards-compatible and therefore at most increase the minor version. -project(libsecp256k1 VERSION 0.3.2 LANGUAGES C) +project(libsecp256k1 + # The package (a.k.a. release) version is based on semantic versioning 2.0.0 of + # the API. All changes in experimental modules are treated as + # backwards-compatible and therefore at most increase the minor version. + VERSION 0.3.2 + DESCRIPTION "Optimized C library for ECDSA signatures and secret/public key operations on curve secp256k1." + HOMEPAGE_URL "https://github.com/bitcoin-core/secp256k1" + LANGUAGES C +) # The library version is based on libtool versioning of the ABI. The set of # rules for updating the version can be found here: From 8c2017035a9c0722aeb7f24162d57d795443fd4c Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Sun, 26 Mar 2023 13:00:32 +0100 Subject: [PATCH 017/100] cmake: Use recommended `add_compile_definitions` command Available in CMake 3.12+. --- CMakeLists.txt | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 92ecf31759..92ec611f6e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,27 +41,27 @@ option(SECP256K1_INSTALL "Enable installation" ON) option(SECP256K1_ENABLE_MODULE_ECDH "Enable ECDH module." ON) if(SECP256K1_ENABLE_MODULE_ECDH) - add_definitions(-DENABLE_MODULE_ECDH=1) + add_compile_definitions(ENABLE_MODULE_ECDH=1) endif() option(SECP256K1_ENABLE_MODULE_RECOVERY "Enable ECDSA pubkey recovery module." OFF) if(SECP256K1_ENABLE_MODULE_RECOVERY) - add_definitions(-DENABLE_MODULE_RECOVERY=1) + add_compile_definitions(ENABLE_MODULE_RECOVERY=1) endif() option(SECP256K1_ENABLE_MODULE_EXTRAKEYS "Enable extrakeys module." ON) option(SECP256K1_ENABLE_MODULE_SCHNORRSIG "Enable schnorrsig module." ON) if(SECP256K1_ENABLE_MODULE_SCHNORRSIG) set(SECP256K1_ENABLE_MODULE_EXTRAKEYS ON) - add_definitions(-DENABLE_MODULE_SCHNORRSIG=1) + add_compile_definitions(ENABLE_MODULE_SCHNORRSIG=1) endif() if(SECP256K1_ENABLE_MODULE_EXTRAKEYS) - add_definitions(-DENABLE_MODULE_EXTRAKEYS=1) + add_compile_definitions(ENABLE_MODULE_EXTRAKEYS=1) endif() option(SECP256K1_USE_EXTERNAL_DEFAULT_CALLBACKS "Enable external default callback functions." OFF) if(SECP256K1_USE_EXTERNAL_DEFAULT_CALLBACKS) - add_definitions(-DUSE_EXTERNAL_DEFAULT_CALLBACKS=1) + add_compile_definitions(USE_EXTERNAL_DEFAULT_CALLBACKS=1) endif() set(SECP256K1_ECMULT_WINDOW_SIZE "AUTO" CACHE STRING "Window size for ecmult precomputation for verification, specified as integer in range [2..24]. \"AUTO\" is a reasonable setting for desktop machines (currently 15). [default=AUTO]") @@ -71,7 +71,7 @@ check_string_option_value(SECP256K1_ECMULT_WINDOW_SIZE) if(SECP256K1_ECMULT_WINDOW_SIZE STREQUAL "AUTO") set(SECP256K1_ECMULT_WINDOW_SIZE 15) endif() -add_definitions(-DECMULT_WINDOW_SIZE=${SECP256K1_ECMULT_WINDOW_SIZE}) +add_compile_definitions(ECMULT_WINDOW_SIZE=${SECP256K1_ECMULT_WINDOW_SIZE}) set(SECP256K1_ECMULT_GEN_PREC_BITS "AUTO" CACHE STRING "Precision bits to tune the precomputed table size for signing, specified as integer 2, 4 or 8. \"AUTO\" is a reasonable setting for desktop machines (currently 4). [default=AUTO]") set_property(CACHE SECP256K1_ECMULT_GEN_PREC_BITS PROPERTY STRINGS "AUTO" 2 4 8) @@ -79,14 +79,14 @@ check_string_option_value(SECP256K1_ECMULT_GEN_PREC_BITS) if(SECP256K1_ECMULT_GEN_PREC_BITS STREQUAL "AUTO") set(SECP256K1_ECMULT_GEN_PREC_BITS 4) endif() -add_definitions(-DECMULT_GEN_PREC_BITS=${SECP256K1_ECMULT_GEN_PREC_BITS}) +add_compile_definitions(ECMULT_GEN_PREC_BITS=${SECP256K1_ECMULT_GEN_PREC_BITS}) set(SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY "OFF" CACHE STRING "Test-only override of the (autodetected by the C code) \"widemul\" setting. Legal values are: \"OFF\", \"int128_struct\", \"int128\" or \"int64\". [default=OFF]") set_property(CACHE SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY PROPERTY STRINGS "OFF" "int128_struct" "int128" "int64") check_string_option_value(SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY) if(SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY) string(TOUPPER "${SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY}" widemul_upper_value) - add_definitions(-DUSE_FORCE_WIDEMUL_${widemul_upper_value}=1) + add_compile_definitions(USE_FORCE_WIDEMUL_${widemul_upper_value}=1) endif() mark_as_advanced(FORCE SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY) @@ -95,13 +95,13 @@ set_property(CACHE SECP256K1_ASM PROPERTY STRINGS "AUTO" "OFF" "x86_64" "arm") check_string_option_value(SECP256K1_ASM) if(SECP256K1_ASM STREQUAL "arm") enable_language(ASM) - add_definitions(-DUSE_EXTERNAL_ASM=1) + add_compile_definitions(USE_EXTERNAL_ASM=1) elseif(SECP256K1_ASM) include(Check64bitAssembly) check_64bit_assembly() if(HAS_64BIT_ASM) set(SECP256K1_ASM "x86_64") - add_definitions(-DUSE_ASM_X86_64=1) + add_compile_definitions(USE_ASM_X86_64=1) elseif(SECP256K1_ASM STREQUAL "AUTO") set(SECP256K1_ASM "OFF") else() @@ -124,7 +124,7 @@ if(SECP256K1_VALGRIND) if(Valgrind_FOUND) set(SECP256K1_VALGRIND ON) include_directories(${Valgrind_INCLUDE_DIR}) - add_definitions(-DVALGRIND) + add_compile_definitions(VALGRIND) elseif(SECP256K1_VALGRIND STREQUAL "AUTO") set(SECP256K1_VALGRIND OFF) else() From 9f8703ef17db0144b320714cd56c1fe0317a5786 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Sun, 26 Mar 2023 13:00:52 +0100 Subject: [PATCH 018/100] cmake: Use dedicated `CMAKE_HOST_APPLE` variable --- cmake/FindValgrind.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/FindValgrind.cmake b/cmake/FindValgrind.cmake index f6c1f58649..3af5e691e4 100644 --- a/cmake/FindValgrind.cmake +++ b/cmake/FindValgrind.cmake @@ -1,4 +1,4 @@ -if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin") +if(CMAKE_HOST_APPLE) find_program(BREW_COMMAND brew) execute_process( COMMAND ${BREW_COMMAND} --prefix valgrind From 2445808c0203215e7182355762944ab909d423d2 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Sun, 26 Mar 2023 13:15:34 +0100 Subject: [PATCH 019/100] cmake: Use dedicated `GENERATOR_IS_MULTI_CONFIG` property Available in CMake 3.9+. --- CMakeLists.txt | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 92ec611f6e..5308ee257c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -171,21 +171,24 @@ mark_as_advanced( CMAKE_SHARED_LINKER_FLAGS_COVERAGE ) -if(CMAKE_CONFIGURATION_TYPES) - set(CMAKE_CONFIGURATION_TYPES "RelWithDebInfo" "Release" "Debug" "MinSizeRel" "Coverage") -endif() - -get_property(cached_cmake_build_type CACHE CMAKE_BUILD_TYPE PROPERTY TYPE) -if(cached_cmake_build_type) +get_property(is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) +set(default_build_type "RelWithDebInfo") +if(is_multi_config) + set(CMAKE_CONFIGURATION_TYPES "${default_build_type}" "Release" "Debug" "MinSizeRel" "Coverage" CACHE STRING + "Supported configuration types." + FORCE + ) +else() set_property(CACHE CMAKE_BUILD_TYPE PROPERTY - STRINGS "RelWithDebInfo" "Release" "Debug" "MinSizeRel" "Coverage" + STRINGS "${default_build_type}" "Release" "Debug" "MinSizeRel" "Coverage" ) -endif() - -set(default_build_type "RelWithDebInfo") -if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) - message(STATUS "Setting build type to \"${default_build_type}\" as none was specified") - set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE STRING "Choose the type of build." FORCE) + if(NOT CMAKE_BUILD_TYPE) + message(STATUS "Setting build type to \"${default_build_type}\" as none was specified") + set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE STRING + "Choose the type of build." + FORCE + ) + endif() endif() include(TryAddCompileOption) @@ -279,7 +282,7 @@ message("CFLAGS ................................ ${CMAKE_C_FLAGS}") get_directory_property(compile_options COMPILE_OPTIONS) string(REPLACE ";" " " compile_options "${compile_options}") message("Compile options ....................... " ${compile_options}) -if(DEFINED CMAKE_BUILD_TYPE) +if(NOT is_multi_config) message("Build type:") message(" - CMAKE_BUILD_TYPE ................... ${CMAKE_BUILD_TYPE}") string(TOUPPER "${CMAKE_BUILD_TYPE}" build_type) @@ -287,7 +290,7 @@ if(DEFINED CMAKE_BUILD_TYPE) message(" - LDFLAGS for executables ............ ${CMAKE_EXE_LINKER_FLAGS_${build_type}}") message(" - LDFLAGS for shared libraries ....... ${CMAKE_SHARED_LINKER_FLAGS_${build_type}}") else() - message("Available configurations .............. ${CMAKE_CONFIGURATION_TYPES}") + message("Supported configurations .............. ${CMAKE_CONFIGURATION_TYPES}") message("RelWithDebInfo configuration:") message(" - CFLAGS ............................. ${CMAKE_C_FLAGS_RELWITHDEBINFO}") message(" - LDFLAGS for executables ............ ${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO}") From 6a58b483efb96de32134611963c16f6bf7e94d51 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Sun, 26 Mar 2023 20:08:12 +0100 Subject: [PATCH 020/100] cmake: Use `if(... IN_LIST ...)` command Available in CMake 3.3+. --- cmake/CheckStringOptionValue.cmake | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/cmake/CheckStringOptionValue.cmake b/cmake/CheckStringOptionValue.cmake index bc4d7b5749..5a4d939b9e 100644 --- a/cmake/CheckStringOptionValue.cmake +++ b/cmake/CheckStringOptionValue.cmake @@ -1,11 +1,9 @@ function(check_string_option_value option) get_property(expected_values CACHE ${option} PROPERTY STRINGS) if(expected_values) - foreach(value IN LISTS expected_values) - if(value STREQUAL "${${option}}") - return() - endif() - endforeach() + if(${option} IN_LIST expected_values) + return() + endif() message(FATAL_ERROR "${option} value is \"${${option}}\", but must be one of ${expected_values}.") endif() message(AUTHOR_WARNING "The STRINGS property must be set before invoking `check_string_option_value' function.") From a273d74b2ea1ef115a7e40fe89a64a6c744018c6 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Thu, 20 Apr 2023 17:03:42 +0100 Subject: [PATCH 021/100] cmake: Improve version comparison --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5308ee257c..fe716c8bde 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.13) -if(CMAKE_VERSION VERSION_GREATER 3.14) +if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.15) # MSVC runtime library flags are selected by the CMAKE_MSVC_RUNTIME_LIBRARY abstraction. cmake_policy(SET CMP0091 NEW) # MSVC warning flags are not in CMAKE__FLAGS by default. From 0a446a312fdd6260320eeed51697ecadf61ee11f Mon Sep 17 00:00:00 2001 From: Tim Ruffing Date: Fri, 10 Mar 2023 10:51:26 +0100 Subject: [PATCH 022/100] cmake: Add dev-mode CMake preset To use, invoke `cmake` with argument `--preset dev-mode`. Solves one item in #1235. One disadvantage over `./configure --enable-dev-mode` is that CMake does not provide a way to "hide" presets from users. That is, `cmake --list-presets` will list dev-mode, and it will also appear in `cmake-gui`, even though it's not selectable there due to bug https://gitlab.kitware.com/cmake/cmake/-/issues/23341. (So in our case, that's probably rather a feature than a bug.) We curently use version 3 presets which require CMake 3.21+. Unfortunately, CMake versions before 3.19 may ignore the `--preset` argument silently. So if the preset is not picked up, make sure you have a recent enough CMake version. More unfortunately, we can't even spell this warning out in CMakePresets.json because CMake does not support officially support comments in JSON, see - https://gitlab.kitware.com/cmake/cmake/-/issues/21858 - https://gitlab.kitware.com/cmake/cmake/-/merge_requests/5853 . We could use a hack hinted at in https://gitlab.kitware.com/cmake/cmake/-/issues/21858#note_908543 but that's risky, because it could simply break for future versions, and we probably want to use presets not only for dev mode. --- CMakePresets.json | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 CMakePresets.json diff --git a/CMakePresets.json b/CMakePresets.json new file mode 100644 index 0000000000..b35cd80579 --- /dev/null +++ b/CMakePresets.json @@ -0,0 +1,19 @@ +{ + "cmakeMinimumRequired": {"major": 3, "minor": 21, "patch": 0}, + "version": 3, + "configurePresets": [ + { + "name": "dev-mode", + "displayName": "Development mode (intended only for developers of the library)", + "cacheVariables": { + "SECP256K1_EXPERIMENTAL": "ON", + "SECP256K1_ENABLE_MODULE_RECOVERY": "ON", + "SECP256K1_BUILD_EXAMPLES": "ON" + }, + "warnings": { + "dev": true, + "uninitialized": true + } + } + ] +} From ce5ba9e24dfcceb49ed7f83a87548fd8b3b0cab2 Mon Sep 17 00:00:00 2001 From: Tim Ruffing Date: Thu, 16 Mar 2023 22:58:24 +0900 Subject: [PATCH 023/100] gitignore: Add CMakeUserPresets.json This file is specifically intended for *local* CMake templates (as opposed to CMakePresets.json). --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index bc7e499de7..574902b8b5 100644 --- a/.gitignore +++ b/.gitignore @@ -59,5 +59,7 @@ build-aux/compile build-aux/test-driver libsecp256k1.pc +### CMake +/CMakeUserPresets.json # Default CMake build directory. /build From 69e1ec033120497b83dd95d92166fa05c54b8a06 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Thu, 20 Apr 2023 16:07:35 -0400 Subject: [PATCH 024/100] Get rid of secp256k1_fe_const_b --- src/group_impl.h | 2 -- src/tests.c | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/group_impl.h b/src/group_impl.h index 7ec069a80c..29017dc965 100644 --- a/src/group_impl.h +++ b/src/group_impl.h @@ -73,8 +73,6 @@ static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_G; #endif /* End of section generated by sage/gen_exhaustive_groups.sage. */ -static const secp256k1_fe secp256k1_fe_const_b = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, SECP256K1_B); - static void secp256k1_ge_set_gej_zinv(secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zi) { secp256k1_fe zi2; secp256k1_fe zi3; diff --git a/src/tests.c b/src/tests.c index 4c1946a5bd..9b3c92dd6e 100644 --- a/src/tests.c +++ b/src/tests.c @@ -4498,7 +4498,7 @@ static void ecmult_const_mult_xonly(void) { random_field_element_test(&x); secp256k1_fe_sqr(&c, &x); secp256k1_fe_mul(&c, &c, &x); - secp256k1_fe_add(&c, &secp256k1_fe_const_b); + secp256k1_fe_add_int(&c, SECP256K1_B); } while (secp256k1_fe_is_square_var(&c)); /* If i is odd, n=d*x for random non-zero d. */ if (i & 1) { From 162608cc982538906e775d0c549aff2de5dee413 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Thu, 20 Apr 2023 23:12:28 +0100 Subject: [PATCH 025/100] cmake: Emulate `PROJECT_IS_TOP_LEVEL` for CMake<3.21 --- CMakeLists.txt | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 91d2bed02c..0c8f049ae5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,6 +12,18 @@ endif() # backwards-compatible and therefore at most increase the minor version. project(libsecp256k1 VERSION 0.3.2 LANGUAGES C) +if(CMAKE_VERSION VERSION_LESS 3.21) + get_directory_property(parent_directory PARENT_DIRECTORY) + if(parent_directory) + set(PROJECT_IS_TOP_LEVEL OFF CACHE INTERNAL "Emulates CMake 3.21+ behavior.") + set(${PROJECT_NAME}_IS_TOP_LEVEL OFF CACHE INTERNAL "Emulates CMake 3.21+ behavior.") + else() + set(PROJECT_IS_TOP_LEVEL ON CACHE INTERNAL "Emulates CMake 3.21+ behavior.") + set(${PROJECT_NAME}_IS_TOP_LEVEL ON CACHE INTERNAL "Emulates CMake 3.21+ behavior.") + endif() + unset(parent_directory) +endif() + # The library version is based on libtool versioning of the ABI. The set of # rules for updating the version can be found here: # https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html From 68b16a1662af2db801a87d6f1afedca93ec2501c Mon Sep 17 00:00:00 2001 From: Tim Ruffing Date: Fri, 21 Apr 2023 11:18:36 +0200 Subject: [PATCH 026/100] bench: Make sys/time.h a system include --- src/bench.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bench.h b/src/bench.h index bf9a932ff4..1564b1a176 100644 --- a/src/bench.h +++ b/src/bench.h @@ -15,7 +15,7 @@ #if (defined(_MSC_VER) && _MSC_VER >= 1900) # include #else -# include "sys/time.h" +# include #endif static int64_t gettime_i64(void) { From 5431b9decdbbdf30c5c5f2aed4b59662f5c681a2 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Fri, 21 Apr 2023 12:03:04 +0100 Subject: [PATCH 027/100] cmake: Make `SECP256K1_INSTALL` default depend on `PROJECT_IS_TOP_LEVEL` Also full stops have been added to the option help texts for consistency in cmake-gui. --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0c8f049ae5..0b588ac98b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,13 +38,13 @@ set(CMAKE_C_EXTENSIONS OFF) list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake) -option(BUILD_SHARED_LIBS "Build shared libraries" ON) +option(BUILD_SHARED_LIBS "Build shared libraries." ON) option(SECP256K1_DISABLE_SHARED "Disable shared library. Overrides BUILD_SHARED_LIBS." OFF) if(SECP256K1_DISABLE_SHARED) set(BUILD_SHARED_LIBS OFF) endif() -option(SECP256K1_INSTALL "Enable installation" ON) +option(SECP256K1_INSTALL "Enable installation." ${PROJECT_IS_TOP_LEVEL}) option(SECP256K1_ENABLE_MODULE_ECDH "Enable ECDH module." ON) if(SECP256K1_ENABLE_MODULE_ECDH) From e9fd3dff76e30fcd83d060ad9195cadae9cdc9a2 Mon Sep 17 00:00:00 2001 From: Tim Ruffing Date: Wed, 1 Feb 2023 12:26:57 +0100 Subject: [PATCH 028/100] field: Improve docs and tests of secp256k1_fe_set_b32 --- src/field.h | 4 +++- src/tests.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 1 deletion(-) diff --git a/src/field.h b/src/field.h index 4b57548bea..d02a4d9bed 100644 --- a/src/field.h +++ b/src/field.h @@ -75,7 +75,9 @@ static int secp256k1_fe_equal_var(const secp256k1_fe *a, const secp256k1_fe *b); /** Compare two field elements. Requires both inputs to be normalized */ static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b); -/** Set a field element equal to 32-byte big endian value. If successful, the resulting field element is normalized. */ +/** Set a field element equal to 32-byte big endian value. + * Returns 1 if no overflow occurred, and then the output is normalized. + * Returns 0 if overflow occurred, and then the output is only weakly normalized. */ static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a); /** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */ diff --git a/src/tests.c b/src/tests.c index bc5b7cb1f1..154e700b0f 100644 --- a/src/tests.c +++ b/src/tests.c @@ -2961,6 +2961,69 @@ static void run_field_convert(void) { CHECK(secp256k1_memcmp_var(&fes2, &fes, sizeof(fes)) == 0); } +static void run_field_be32_overflow(void) { + { + static const unsigned char zero_overflow[32] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFC, 0x2F, + }; + static const unsigned char zero[32] = { 0x00 }; + unsigned char out[32]; + secp256k1_fe fe; + CHECK(secp256k1_fe_set_b32(&fe, zero_overflow) == 0); + CHECK(secp256k1_fe_normalizes_to_zero(&fe) == 1); + secp256k1_fe_normalize(&fe); + CHECK(secp256k1_fe_is_zero(&fe) == 1); + secp256k1_fe_get_b32(out, &fe); + CHECK(secp256k1_memcmp_var(out, zero, 32) == 0); + } + { + static const unsigned char one_overflow[32] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFC, 0x30, + }; + static const unsigned char one[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + }; + unsigned char out[32]; + secp256k1_fe fe; + CHECK(secp256k1_fe_set_b32(&fe, one_overflow) == 0); + secp256k1_fe_normalize(&fe); + CHECK(secp256k1_fe_cmp_var(&fe, &secp256k1_fe_one) == 0); + secp256k1_fe_get_b32(out, &fe); + CHECK(secp256k1_memcmp_var(out, one, 32) == 0); + } + { + static const unsigned char ff_overflow[32] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + }; + static const unsigned char ff[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0xD0, + }; + unsigned char out[32]; + secp256k1_fe fe; + const secp256k1_fe fe_ff = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0x01, 0x000003d0); + CHECK(secp256k1_fe_set_b32(&fe, ff_overflow) == 0); + secp256k1_fe_normalize(&fe); + CHECK(secp256k1_fe_cmp_var(&fe, &fe_ff) == 0); + secp256k1_fe_get_b32(out, &fe); + CHECK(secp256k1_memcmp_var(out, ff, 32) == 0); + } +} + /* Returns true if two field elements have the same representation. */ static int fe_identical(const secp256k1_fe *a, const secp256k1_fe *b) { int ret = 1; @@ -7515,6 +7578,7 @@ int main(int argc, char **argv) { run_field_half(); run_field_misc(); run_field_convert(); + run_field_be32_overflow(); run_fe_mul(); run_sqr(); run_sqrt(); From 162da73e9a48875aab1ee6ca1c14f86ca4646946 Mon Sep 17 00:00:00 2001 From: Tim Ruffing Date: Wed, 1 Feb 2023 14:30:00 +0100 Subject: [PATCH 029/100] tests: Add debug helper for printing buffers --- src/tests.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/tests.c b/src/tests.c index 154e700b0f..ce991e1640 100644 --- a/src/tests.c +++ b/src/tests.c @@ -44,6 +44,25 @@ static int all_bytes_equal(const void* s, unsigned char value, size_t n) { return 1; } +/* Debug helper for printing arrays of unsigned char. */ +#define PRINT_BUF(buf, len) do { \ + printf("%s[%lu] = ", #buf, (unsigned long)len); \ + print_buf_plain(buf, len); \ +} while(0); +static void print_buf_plain(const unsigned char *buf, size_t len) { + size_t i; + printf("{"); + for (i = 0; i < len; i++) { + if (i % 8 == 0) { + printf("\n "); + } else { + printf(" "); + } + printf("0x%02X,", buf[i]); + } + printf("\n}\n"); +} + /* TODO Use CHECK_ILLEGAL(_VOID) everywhere and get rid of the uncounting callback */ /* CHECK that expr_or_stmt calls the illegal callback of ctx exactly once * From 3858bad2c6493aa66cbfa62540d89da9c5a16040 Mon Sep 17 00:00:00 2001 From: Jonas Nick Date: Fri, 21 Apr 2023 20:21:28 +0000 Subject: [PATCH 030/100] tests: remove extra semicolon in macro --- src/tests.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/tests.c b/src/tests.c index 0f9c35faf2..24355039b3 100644 --- a/src/tests.c +++ b/src/tests.c @@ -48,7 +48,8 @@ static int all_bytes_equal(const void* s, unsigned char value, size_t n) { #define PRINT_BUF(buf, len) do { \ printf("%s[%lu] = ", #buf, (unsigned long)len); \ print_buf_plain(buf, len); \ -} while(0); +} while(0) + static void print_buf_plain(const unsigned char *buf, size_t len) { size_t i; printf("{"); From e1b9ce881159e8e2572467f1426f200e987a4d44 Mon Sep 17 00:00:00 2001 From: Tim Ruffing Date: Fri, 14 Apr 2023 07:37:10 +0200 Subject: [PATCH 031/100] autotools: Use same conventions for all pregenerated files --- Makefile.am | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Makefile.am b/Makefile.am index 20024e474e..f745013c93 100644 --- a/Makefile.am +++ b/Makefile.am @@ -203,7 +203,7 @@ precompute_ecmult_gen_LDADD = $(COMMON_LIB) # otherwise make's decision whether to rebuild them (even in the first # build by a normal user) depends on mtimes, and thus is very fragile. # This means that rebuilds of the prebuilt files always need to be -# forced by deleting them, e.g., by invoking `make clean-precomp`. +# forced by deleting them. src/precomputed_ecmult.c: $(MAKE) $(AM_MAKEFLAGS) precompute_ecmult$(EXEEXT) ./precompute_ecmult$(EXEEXT) @@ -224,6 +224,7 @@ clean-precomp: rm -f $(PRECOMP) ### Pregenerated test vectors +### (see the comments in the previous section for detailed rationale) TESTVECTORS = src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.h src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.h: @@ -231,7 +232,9 @@ src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.h: testvectors: $(TESTVECTORS) -maintainer-clean-testvectors: clean-testvectors +BUILT_SOURCES += $(TESTVECTORS) + +maintainer-clean-local: clean-testvectors clean-testvectors: rm -f $(TESTVECTORS) From 8764034ed55bffc8a26fbe377ac505359f8828e9 Mon Sep 17 00:00:00 2001 From: Tim Ruffing Date: Fri, 14 Apr 2023 07:45:49 +0200 Subject: [PATCH 032/100] autotools: Make all "pregenerated" targets .PHONY This follows the automake conventions more, see: https://www.gnu.org/software/automake/manual/html_node/Clean.html --- Makefile.am | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/Makefile.am b/Makefile.am index f745013c93..6e2aa7fe01 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,5 +1,3 @@ -.PHONY: clean-precomp precomp - ACLOCAL_AMFLAGS = -I build-aux/m4 # AM_CFLAGS will be automatically prepended to CFLAGS by Automake when compiling some foo @@ -218,10 +216,10 @@ precomp: $(PRECOMP) # e.g., after `make maintainer-clean`). BUILT_SOURCES = $(PRECOMP) -maintainer-clean-local: clean-precomp - +.PHONY: clean-precomp clean-precomp: rm -f $(PRECOMP) +maintainer-clean-local: clean-precomp ### Pregenerated test vectors ### (see the comments in the previous section for detailed rationale) @@ -234,10 +232,10 @@ testvectors: $(TESTVECTORS) BUILT_SOURCES += $(TESTVECTORS) -maintainer-clean-local: clean-testvectors - +.PHONY: clean-testvectors clean-testvectors: rm -f $(TESTVECTORS) +maintainer-clean-local: clean-testvectors ### Additional files to distribute EXTRA_DIST = autogen.sh CHANGELOG.md SECURITY.md From 2418d3260ac51ba0f148fb20e19c8f41bba8a135 Mon Sep 17 00:00:00 2001 From: Tim Ruffing Date: Fri, 14 Apr 2023 07:54:24 +0200 Subject: [PATCH 033/100] autotools: Create src/wycheproof dir before creating file in it This directory may not exist in a VPATH build, see https://github.com/bitcoin/bitcoin/pull/27445#issuecomment-1502994264 . --- Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile.am b/Makefile.am index 6e2aa7fe01..047b2f2178 100644 --- a/Makefile.am +++ b/Makefile.am @@ -226,6 +226,7 @@ maintainer-clean-local: clean-precomp TESTVECTORS = src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.h src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.h: + mkdir -p $(@D) python3 tools/tests_wycheproof_generate.py src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.json > $@ testvectors: $(TESTVECTORS) From 7e977b3c5071fc17575ff88ebbc9db7b17c70497 Mon Sep 17 00:00:00 2001 From: Tim Ruffing Date: Tue, 25 Apr 2023 11:44:25 +0100 Subject: [PATCH 034/100] autotools: Take VPATH builds into account when generating testvectors --- Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index 047b2f2178..29b8a69cfb 100644 --- a/Makefile.am +++ b/Makefile.am @@ -227,7 +227,7 @@ TESTVECTORS = src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.h src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.h: mkdir -p $(@D) - python3 tools/tests_wycheproof_generate.py src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.json > $@ + python3 $(top_srcdir)/tools/tests_wycheproof_generate.py $(top_srcdir)/src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.json > $@ testvectors: $(TESTVECTORS) From c4062d6b5d83572c1932f32003a7c0e901fffc23 Mon Sep 17 00:00:00 2001 From: Jonas Nick Date: Tue, 25 Apr 2023 16:07:10 +0000 Subject: [PATCH 035/100] debug: move helper for printing buffers into util.h --- src/tests.c | 20 -------------------- src/util.h | 20 ++++++++++++++++++++ 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/tests.c b/src/tests.c index 24355039b3..6d46b39d74 100644 --- a/src/tests.c +++ b/src/tests.c @@ -44,26 +44,6 @@ static int all_bytes_equal(const void* s, unsigned char value, size_t n) { return 1; } -/* Debug helper for printing arrays of unsigned char. */ -#define PRINT_BUF(buf, len) do { \ - printf("%s[%lu] = ", #buf, (unsigned long)len); \ - print_buf_plain(buf, len); \ -} while(0) - -static void print_buf_plain(const unsigned char *buf, size_t len) { - size_t i; - printf("{"); - for (i = 0; i < len; i++) { - if (i % 8 == 0) { - printf("\n "); - } else { - printf(" "); - } - printf("0x%02X,", buf[i]); - } - printf("\n}\n"); -} - /* TODO Use CHECK_ILLEGAL(_VOID) everywhere and get rid of the uncounting callback */ /* CHECK that expr_or_stmt calls the illegal callback of ctx exactly once * diff --git a/src/util.h b/src/util.h index f980f47bdc..0e3faf0234 100644 --- a/src/util.h +++ b/src/util.h @@ -19,6 +19,26 @@ #define DEBUG_CONFIG_MSG(x) "DEBUG_CONFIG: " x #define DEBUG_CONFIG_DEF(x) DEBUG_CONFIG_MSG(#x "=" STR(x)) +/* Debug helper for printing arrays of unsigned char. */ +#define PRINT_BUF(buf, len) do { \ + printf("%s[%lu] = ", #buf, (unsigned long)len); \ + print_buf_plain(buf, len); \ +} while(0) + +static void print_buf_plain(const unsigned char *buf, size_t len) { + size_t i; + printf("{"); + for (i = 0; i < len; i++) { + if (i % 8 == 0) { + printf("\n "); + } else { + printf(" "); + } + printf("0x%02X,", buf[i]); + } + printf("\n}\n"); +} + # if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) ) # if SECP256K1_GNUC_PREREQ(2,7) # define SECP256K1_INLINE __inline__ From 19516ed3e9efe43b00d75820fb6590dcbed548b3 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Thu, 27 Apr 2023 14:39:10 +0100 Subject: [PATCH 036/100] cmake: Use `add_compile_options()` in `try_add_compile_option()` This change drops tinkering with the `COMPILE_OPTIONS` directory property. Also `try_add_compile_option()` can handle a list of flags now, if they are required to be checked simultaneously. An explanatory comments have been added as well. --- cmake/TryAddCompileOption.cmake | 35 +++++++++++++++++---------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/cmake/TryAddCompileOption.cmake b/cmake/TryAddCompileOption.cmake index f53c252c2d..9a99e4f2ee 100644 --- a/cmake/TryAddCompileOption.cmake +++ b/cmake/TryAddCompileOption.cmake @@ -1,23 +1,24 @@ include(CheckCCompilerFlag) -function(try_add_compile_option option) - string(MAKE_C_IDENTIFIER ${option} result) - string(TOUPPER ${result} result) - set(result "C_SUPPORTS${result}") - set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) +function(secp256k1_check_c_flags_internal flags output) + string(MAKE_C_IDENTIFIER "${flags}" result) + string(TOUPPER "${result}" result) + set(result "C_SUPPORTS_${result}") if(NOT MSVC) set(CMAKE_REQUIRED_FLAGS "-Werror") endif() - check_c_compiler_flag(${option} ${result}) - if(${result}) - get_property(compile_options - DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" - PROPERTY COMPILE_OPTIONS - ) - list(APPEND compile_options "${option}") - set_property( - DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" - PROPERTY COMPILE_OPTIONS "${compile_options}" - ) - endif() + + # This avoids running a linker. + set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) + check_c_compiler_flag("${flags}" ${result}) + + set(${output} ${${result}} PARENT_SCOPE) endfunction() + +# Append flags to the COMPILE_OPTIONS directory property if CC accepts them. +macro(try_add_compile_option) + secp256k1_check_c_flags_internal("${ARGV}" result) + if(result) + add_compile_options(${ARGV}) + endif() +endmacro() From 6ece1507cb11a897a98052f34a374ec00e83cb86 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Wed, 22 Mar 2023 10:35:49 +0000 Subject: [PATCH 037/100] cmake, refactor: Rename `try_add_compile_option` to `try_append_cflags` Actually, `try_append_cflags()` can handle a list of flags, and the new name is similar to the one used in `configure.ac`. --- CMakeLists.txt | 34 +++++++++---------- ...pileOption.cmake => TryAppendCFlags.cmake} | 2 +- 2 files changed, 18 insertions(+), 18 deletions(-) rename cmake/{TryAddCompileOption.cmake => TryAppendCFlags.cmake} (95%) diff --git a/CMakeLists.txt b/CMakeLists.txt index fe716c8bde..ac18cf83e6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -191,25 +191,25 @@ else() endif() endif() -include(TryAddCompileOption) +include(TryAppendCFlags) if(MSVC) - try_add_compile_option(/W2) - try_add_compile_option(/wd4146) + try_append_c_flags(/W2) + try_append_c_flags(/wd4146) else() - try_add_compile_option(-pedantic) - try_add_compile_option(-Wall) - try_add_compile_option(-Wcast-align) - try_add_compile_option(-Wcast-align=strict) - try_add_compile_option(-Wconditional-uninitialized) - try_add_compile_option(-Wextra) - try_add_compile_option(-Wnested-externs) - try_add_compile_option(-Wno-long-long) - try_add_compile_option(-Wno-overlength-strings) - try_add_compile_option(-Wno-unused-function) - try_add_compile_option(-Wreserved-identifier) - try_add_compile_option(-Wshadow) - try_add_compile_option(-Wstrict-prototypes) - try_add_compile_option(-Wundef) + try_append_c_flags(-pedantic) + try_append_c_flags(-Wall) + try_append_c_flags(-Wcast-align) + try_append_c_flags(-Wcast-align=strict) + try_append_c_flags(-Wconditional-uninitialized) + try_append_c_flags(-Wextra) + try_append_c_flags(-Wnested-externs) + try_append_c_flags(-Wno-long-long) + try_append_c_flags(-Wno-overlength-strings) + try_append_c_flags(-Wno-unused-function) + try_append_c_flags(-Wreserved-identifier) + try_append_c_flags(-Wshadow) + try_append_c_flags(-Wstrict-prototypes) + try_append_c_flags(-Wundef) endif() set(CMAKE_C_VISIBILITY_PRESET hidden) diff --git a/cmake/TryAddCompileOption.cmake b/cmake/TryAppendCFlags.cmake similarity index 95% rename from cmake/TryAddCompileOption.cmake rename to cmake/TryAppendCFlags.cmake index 9a99e4f2ee..1d81a9317a 100644 --- a/cmake/TryAddCompileOption.cmake +++ b/cmake/TryAppendCFlags.cmake @@ -16,7 +16,7 @@ function(secp256k1_check_c_flags_internal flags output) endfunction() # Append flags to the COMPILE_OPTIONS directory property if CC accepts them. -macro(try_add_compile_option) +macro(try_append_c_flags) secp256k1_check_c_flags_internal("${ARGV}" result) if(result) add_compile_options(${ARGV}) From a8d059f76cb3429381adda1193c3d1976ba3cab4 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Wed, 22 Mar 2023 10:37:16 +0000 Subject: [PATCH 038/100] cmake, doc: Document compiler flags --- CMakeLists.txt | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ac18cf83e6..86ffd931ad 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -193,20 +193,22 @@ endif() include(TryAppendCFlags) if(MSVC) - try_append_c_flags(/W2) - try_append_c_flags(/wd4146) + # Keep the following commands ordered lexicographically. + try_append_c_flags(/W2) # Moderate warning level. + try_append_c_flags(/wd4146) # Disable warning C4146 "unary minus operator applied to unsigned type, result still unsigned". else() + # Keep the following commands ordered lexicographically. try_append_c_flags(-pedantic) - try_append_c_flags(-Wall) - try_append_c_flags(-Wcast-align) - try_append_c_flags(-Wcast-align=strict) - try_append_c_flags(-Wconditional-uninitialized) - try_append_c_flags(-Wextra) + 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. + try_append_c_flags(-Wextra) # GCC >= 3.4, this is the newer name of -W, which we don't use because older GCCs will warn about unused functions. try_append_c_flags(-Wnested-externs) - try_append_c_flags(-Wno-long-long) - try_append_c_flags(-Wno-overlength-strings) - try_append_c_flags(-Wno-unused-function) - try_append_c_flags(-Wreserved-identifier) + try_append_c_flags(-Wno-long-long) # GCC >= 3.0, -Wlong-long is implied by -pedantic. + try_append_c_flags(-Wno-overlength-strings) # GCC >= 4.2, -Woverlength-strings is implied by -pedantic. + try_append_c_flags(-Wno-unused-function) # GCC >= 3.0, -Wunused-function is implied by -Wall. + try_append_c_flags(-Wreserved-identifier) # Clang >= 13.0 only. try_append_c_flags(-Wshadow) try_append_c_flags(-Wstrict-prototypes) try_append_c_flags(-Wundef) From 71f746c057a66d5ae0dfdb5d439bc49592c0d16e Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Fri, 21 Apr 2023 12:03:26 +0100 Subject: [PATCH 039/100] cmake: Include `include` directory for subtree builds --- src/CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index cd1d6f00ee..720377c8ea 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -31,7 +31,9 @@ endif() get_target_property(use_pic secp256k1 POSITION_INDEPENDENT_CODE) set_target_properties(secp256k1_precomputed PROPERTIES POSITION_INDEPENDENT_CODE ${use_pic}) -target_include_directories(secp256k1 PUBLIC +target_include_directories(secp256k1 INTERFACE + # Add the include path for parent projects so that they don't have to manually add it. + $>:${PROJECT_SOURCE_DIR}/include>> $ ) set_target_properties(secp256k1 PROPERTIES From bef448f9af248dba016883401de07b431f3e686e Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Fri, 28 Apr 2023 20:59:53 +0100 Subject: [PATCH 040/100] cmake: Fix library ABI versioning This change emulates Libtool to make sure Libtool and CMake agree on the ABI version. --- src/CMakeLists.txt | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index cd1d6f00ee..e97ca214c5 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -34,10 +34,44 @@ set_target_properties(secp256k1_precomputed PROPERTIES POSITION_INDEPENDENT_CODE target_include_directories(secp256k1 PUBLIC $ ) + +# This emulates Libtool to make sure Libtool and CMake agree on the ABI version, +# see below "Calculate the version variables" in build-aux/ltmain.sh. +math(EXPR ${PROJECT_NAME}_soversion "${${PROJECT_NAME}_LIB_VERSION_CURRENT} - ${${PROJECT_NAME}_LIB_VERSION_AGE}") set_target_properties(secp256k1 PROPERTIES - VERSION "${${PROJECT_NAME}_LIB_VERSION_CURRENT}.${${PROJECT_NAME}_LIB_VERSION_AGE}.${${PROJECT_NAME}_LIB_VERSION_REVISION}" - SOVERSION "${${PROJECT_NAME}_LIB_VERSION_CURRENT}" + SOVERSION ${${PROJECT_NAME}_soversion} ) +if(CMAKE_SYSTEM_NAME STREQUAL "Linux") + set_target_properties(secp256k1 PROPERTIES + VERSION ${${PROJECT_NAME}_soversion}.${${PROJECT_NAME}_LIB_VERSION_AGE}.${${PROJECT_NAME}_LIB_VERSION_REVISION} + ) +elseif(APPLE) + if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.17) + math(EXPR ${PROJECT_NAME}_compatibility_version "${${PROJECT_NAME}_LIB_VERSION_CURRENT} + 1") + set_target_properties(secp256k1 PROPERTIES + MACHO_COMPATIBILITY_VERSION ${${PROJECT_NAME}_compatibility_version} + MACHO_CURRENT_VERSION ${${PROJECT_NAME}_compatibility_version}.${${PROJECT_NAME}_LIB_VERSION_REVISION} + ) + unset(${PROJECT_NAME}_compatibility_version) + elseif(BUILD_SHARED_LIBS) + message(WARNING + "The 'compatibility version' and 'current version' values of the DYLIB " + "will diverge from the values set by the GNU Libtool. To ensure " + "compatibility, it is recommended to upgrade CMake to at least version 3.17." + ) + endif() +elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows") + set(${PROJECT_NAME}_windows "secp256k1") + if(MSVC) + set(${PROJECT_NAME}_windows "${PROJECT_NAME}") + endif() + set_target_properties(secp256k1 PROPERTIES + ARCHIVE_OUTPUT_NAME "${${PROJECT_NAME}_windows}" + RUNTIME_OUTPUT_NAME "${${PROJECT_NAME}_windows}-${${PROJECT_NAME}_soversion}" + ) + unset(${PROJECT_NAME}_windows) +endif() +unset(${PROJECT_NAME}_soversion) if(SECP256K1_BUILD_BENCHMARK) add_executable(bench bench.c) From 755629bc032af155ff68fa820244d04cb80547c5 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Sat, 29 Apr 2023 09:49:25 +0100 Subject: [PATCH 041/100] cmake: Use full signature of `add_test()` command An executable target in the `COMMAND` option will automatically be replaced by the location of the executable created at build time. This change fixes tests for Windows binaries using Wine. --- .cirrus.yml | 2 +- examples/CMakeLists.txt | 6 +++--- src/CMakeLists.txt | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index 0b904a4e38..592500371b 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -403,7 +403,7 @@ task: - cmake --build build --config RelWithDebInfo -- -property:UseMultiToolTask=true;CL_MPcount=5 check_script: - '%x64_NATIVE_TOOLS%' - - ctest --test-dir build -j 5 + - ctest -C RelWithDebInfo --test-dir build -j 5 - build\src\RelWithDebInfo\bench_ecmult.exe - build\src\RelWithDebInfo\bench_internal.exe - build\src\RelWithDebInfo\bench.exe diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 8120f496fa..e095b7f84f 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -12,16 +12,16 @@ endif() add_executable(ecdsa_example ecdsa.c) target_link_libraries(ecdsa_example example) -add_test(ecdsa_example ecdsa_example) +add_test(NAME ecdsa_example COMMAND ecdsa_example) if(SECP256K1_ENABLE_MODULE_ECDH) add_executable(ecdh_example ecdh.c) target_link_libraries(ecdh_example example) - add_test(ecdh_example ecdh_example) + add_test(NAME ecdh_example COMMAND ecdh_example) endif() if(SECP256K1_ENABLE_MODULE_SCHNORRSIG) add_executable(schnorr_example schnorr.c) target_link_libraries(schnorr_example example) - add_test(schnorr_example schnorr_example) + add_test(NAME schnorr_example COMMAND schnorr_example) endif() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 01c5f3a8dc..9d69c90401 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -53,12 +53,12 @@ endif() if(SECP256K1_BUILD_TESTS) add_executable(noverify_tests tests.c) target_link_libraries(noverify_tests secp256k1_precomputed secp256k1_asm) - add_test(noverify_tests noverify_tests) + add_test(NAME 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(tests tests) + add_test(NAME tests COMMAND tests) endif() endif() @@ -67,7 +67,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(exhaustive_tests exhaustive_tests) + add_test(NAME exhaustive_tests COMMAND exhaustive_tests) endif() if(SECP256K1_BUILD_CTIME_TESTS) From b2e29e43d0e5e65c1e1199f86f59689a1e736109 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Sun, 30 Apr 2023 16:46:03 +0100 Subject: [PATCH 042/100] ci: Treat all compiler warnings as errors in "Windows (VS 2022)" task --- .cirrus.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.cirrus.yml b/.cirrus.yml index 592500371b..5b764366f6 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -397,7 +397,7 @@ task: - PowerShell -NoLogo -Command if ($env:CIRRUS_PR -ne $null) { git fetch $env:CIRRUS_REPO_CLONE_URL pull/$env:CIRRUS_PR/merge; git reset --hard FETCH_HEAD; } configure_script: - '%x64_NATIVE_TOOLS%' - - cmake -G "Visual Studio 17 2022" -A x64 -S . -B build -DSECP256K1_ENABLE_MODULE_RECOVERY=ON -DSECP256K1_BUILD_EXAMPLES=ON + - cmake -E env CFLAGS="/WX" cmake -G "Visual Studio 17 2022" -A x64 -S . -B build -DSECP256K1_ENABLE_MODULE_RECOVERY=ON -DSECP256K1_BUILD_EXAMPLES=ON build_script: - '%x64_NATIVE_TOOLS%' - cmake --build build --config RelWithDebInfo -- -property:UseMultiToolTask=true;CL_MPcount=5 From d1e48e5474a2be29e17a477874a4963f8f612a5a Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Sun, 30 Apr 2023 16:53:51 +0100 Subject: [PATCH 043/100] refactor: Make 64-bit shift explicit This change fixes MSVC level-3 warning C4334. See: https://learn.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warning-level-3-c4334 Required to enable level 3 warnings (/W3). --- src/ecmult_impl.h | 2 +- src/tests.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ecmult_impl.h b/src/ecmult_impl.h index a9a63850ef..73ba79ab7d 100644 --- a/src/ecmult_impl.h +++ b/src/ecmult_impl.h @@ -683,7 +683,7 @@ static int secp256k1_ecmult_pippenger_batch(const secp256k1_callback* error_call } state_space->ps = (struct secp256k1_pippenger_point_state *) secp256k1_scratch_alloc(error_callback, scratch, entries * sizeof(*state_space->ps)); state_space->wnaf_na = (int *) secp256k1_scratch_alloc(error_callback, scratch, entries*(WNAF_SIZE(bucket_window+1)) * sizeof(int)); - buckets = (secp256k1_gej *) secp256k1_scratch_alloc(error_callback, scratch, (1<ps == NULL || state_space->wnaf_na == NULL || buckets == NULL) { secp256k1_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint); return 0; diff --git a/src/tests.c b/src/tests.c index 6d46b39d74..da1f0132e4 100644 --- a/src/tests.c +++ b/src/tests.c @@ -2221,7 +2221,7 @@ static void scalar_test(void) { for (i = 0; i < 100; ++i) { int low; int shift = 1 + secp256k1_testrand_int(15); - int expected = r.d[0] % (1 << shift); + int expected = r.d[0] % (1ULL << shift); low = secp256k1_scalar_shr_int(&r, shift); CHECK(expected == low); } From 149c41cee1159fae3928e03be2662b58e9a8e716 Mon Sep 17 00:00:00 2001 From: Sebastian Falbesoner Date: Mon, 8 May 2023 13:00:13 +0200 Subject: [PATCH 044/100] docs: complete interface description for `secp256k1_schnorrsig_sign_custom` For the sake of completeness, add the missing descriptions for the return value and parameters (`ctx`, `sig64`, `keypair`), in the same wording/style as for the function `secp256k1_schnorrsig_sign32`. --- include/secp256k1_schnorrsig.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/include/secp256k1_schnorrsig.h b/include/secp256k1_schnorrsig.h index 733fee5282..cd9845c5f6 100644 --- a/include/secp256k1_schnorrsig.h +++ b/include/secp256k1_schnorrsig.h @@ -144,9 +144,13 @@ SECP256K1_API int secp256k1_schnorrsig_sign( * Creates the same signatures as schnorrsig_sign if msglen is 32 and the * extraparams.ndata is the same as aux_rand32. * + * Returns 1 on success, 0 on failure. + * Args: ctx: pointer to a context object (not secp256k1_context_static). + * Out: sig64: pointer to a 64-byte array to store the serialized signature. * In: msg: the message being signed. Can only be NULL if msglen is 0. - * msglen: length of the message - * extraparams: pointer to a extraparams object (can be NULL) + * msglen: length of the message. + * keypair: pointer to an initialized keypair. + * extraparams: pointer to an extraparams object (can be NULL). */ SECP256K1_API int secp256k1_schnorrsig_sign_custom( const secp256k1_context *ctx, From 2e65f1fdbcc87e2ef8c0baf4abc8ee0f56daf7fe Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Tue, 9 May 2023 14:00:43 -0400 Subject: [PATCH 045/100] Avoid using bench_verify_data as bench_sign_data; merge them --- src/bench.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/src/bench.c b/src/bench.c index 833f70718b..9992056871 100644 --- a/src/bench.c +++ b/src/bench.c @@ -64,11 +64,11 @@ typedef struct { size_t siglen; unsigned char pubkey[33]; size_t pubkeylen; -} bench_verify_data; +} bench_data; static void bench_verify(void* arg, int iters) { int i; - bench_verify_data* data = (bench_verify_data*)arg; + bench_data* data = (bench_data*)arg; for (i = 0; i < iters; i++) { secp256k1_pubkey pubkey; @@ -85,15 +85,9 @@ static void bench_verify(void* arg, int iters) { } } -typedef struct { - secp256k1_context* ctx; - unsigned char msg[32]; - unsigned char key[32]; -} bench_sign_data; - static void bench_sign_setup(void* arg) { int i; - bench_sign_data *data = (bench_sign_data*)arg; + bench_data *data = (bench_data*)arg; for (i = 0; i < 32; i++) { data->msg[i] = i + 1; @@ -105,7 +99,7 @@ static void bench_sign_setup(void* arg) { static void bench_sign_run(void* arg, int iters) { int i; - bench_sign_data *data = (bench_sign_data*)arg; + bench_data *data = (bench_data*)arg; unsigned char sig[74]; for (i = 0; i < iters; i++) { @@ -137,7 +131,7 @@ int main(int argc, char** argv) { int i; secp256k1_pubkey pubkey; secp256k1_ecdsa_signature sig; - bench_verify_data data; + bench_data data; int d = argc == 1; int default_iters = 20000; From a0e696fd4da3788758bb3fdae66c7ae262dbf224 Mon Sep 17 00:00:00 2001 From: Gregory Maxwell Date: Sat, 8 Aug 2020 03:52:34 +0000 Subject: [PATCH 046/100] Make secp256k1_ecmult_const handle infinity Infinity isn't currently needed here, but correctly handling it is a little more safe against future changes. Update docs for it to make it clear that it is not constant time in A (the input point). It never was constant time in Q (and would be a little complicated to make constant time in A). If it was later made constant time in A, infinity support would be easy to preserve, e.g. by running it on a dummy value and cmoving infinity into the output. --- src/ecmult_const.h | 3 +-- src/ecmult_const_impl.h | 5 +++++ src/tests_exhaustive.c | 4 ++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/ecmult_const.h b/src/ecmult_const.h index 9e065d555d..080e04bc88 100644 --- a/src/ecmult_const.h +++ b/src/ecmult_const.h @@ -11,8 +11,7 @@ #include "group.h" /** - * Multiply: R = q*A (in constant-time) - * A must not be infinity. + * Multiply: R = q*A (in constant-time for q) */ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *q); diff --git a/src/ecmult_const_impl.h b/src/ecmult_const_impl.h index f2b6f48285..81e16e343d 100644 --- a/src/ecmult_const_impl.h +++ b/src/ecmult_const_impl.h @@ -144,6 +144,11 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons int i; + if (secp256k1_ge_is_infinity(a)) { + secp256k1_gej_set_infinity(r); + return; + } + /* build wnaf representation for q. */ /* split q into q_1 and q_lam (where q = q_1 + q_lam*lambda, and q_1 and q_lam are ~128 bit) */ secp256k1_scalar_split_lambda(&q_1, &q_lam, scalar); diff --git a/src/tests_exhaustive.c b/src/tests_exhaustive.c index 5a990f7d64..ee60fe9f45 100644 --- a/src/tests_exhaustive.c +++ b/src/tests_exhaustive.c @@ -193,7 +193,7 @@ static void test_exhaustive_ecmult(const secp256k1_ge *group, const secp256k1_ge } for (j = 0; j < EXHAUSTIVE_TEST_ORDER; j++) { - for (i = 1; i < EXHAUSTIVE_TEST_ORDER; i++) { + for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++) { int ret; secp256k1_gej tmp; secp256k1_fe xn, xd, tmpf; @@ -207,7 +207,7 @@ static void test_exhaustive_ecmult(const secp256k1_ge *group, const secp256k1_ge secp256k1_ecmult_const(&tmp, &group[i], &ng); ge_equals_gej(&group[(i * j) % EXHAUSTIVE_TEST_ORDER], &tmp); - if (j != 0) { + if (i != 0 && j != 0) { /* Test secp256k1_ecmult_const_xonly with all curve X coordinates, and xd=NULL. */ ret = secp256k1_ecmult_const_xonly(&tmpf, &group[i].x, NULL, &ng, 0); CHECK(ret); From 3086cb90acd9d61c5b38e862877fdeacaff74a50 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Tue, 1 Sep 2020 16:33:22 -0700 Subject: [PATCH 047/100] Expose secp256k1_fe_verify to other modules --- src/field.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/field.h b/src/field.h index c7a88c4e13..62dc0f3ae0 100644 --- a/src/field.h +++ b/src/field.h @@ -143,4 +143,9 @@ static void secp256k1_fe_get_bounds(secp256k1_fe *r, int m); /** Determine whether a is a square (modulo p). */ static int secp256k1_fe_is_square_var(const secp256k1_fe *a); +#ifdef VERIFY +/** Check invariants on a field element. */ +static void secp256k1_fe_verify(const secp256k1_fe *a); +#endif + #endif /* SECP256K1_FIELD_H */ From a18821d5b1d44db0e7c8335f338cc9876bec98cb Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Tue, 1 Sep 2020 18:15:21 -0700 Subject: [PATCH 048/100] Always initialize output coordinates in secp256k1_ge_set_gej --- src/group_impl.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/group_impl.h b/src/group_impl.h index 29017dc965..d6031e58cf 100644 --- a/src/group_impl.h +++ b/src/group_impl.h @@ -115,10 +115,11 @@ static void secp256k1_ge_set_gej(secp256k1_ge *r, secp256k1_gej *a) { static void secp256k1_ge_set_gej_var(secp256k1_ge *r, secp256k1_gej *a) { secp256k1_fe z2, z3; - if (a->infinity) { + if (secp256k1_gej_is_infinity(a)) { secp256k1_ge_set_infinity(r); return; } + r->infinity = 0; secp256k1_fe_inv_var(&a->z, &a->z); secp256k1_fe_sqr(&z2, &a->z); secp256k1_fe_mul(&z3, &a->z, &z2); From f20266722ac93ca66d1beb0d2f2d2469b95aafea Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Tue, 1 Sep 2020 17:59:51 -0700 Subject: [PATCH 049/100] Add invariant checking to group elements --- src/group.h | 8 ++ src/group_impl.h | 188 +++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 191 insertions(+), 5 deletions(-) diff --git a/src/group.h b/src/group.h index b79ba597db..14cdb4062d 100644 --- a/src/group.h +++ b/src/group.h @@ -164,4 +164,12 @@ static void secp256k1_gej_rescale(secp256k1_gej *r, const secp256k1_fe *b); */ static int secp256k1_ge_is_in_correct_subgroup(const secp256k1_ge* ge); +#ifdef VERIFY +/** Check invariants on an affine group element. */ +static void secp256k1_ge_verify(const secp256k1_ge *a); + +/** Check invariants on a Jacobian group element. */ +static void secp256k1_gej_verify(const secp256k1_gej *a); +#endif + #endif /* SECP256K1_GROUP_H */ diff --git a/src/group_impl.h b/src/group_impl.h index d6031e58cf..86be92d59d 100644 --- a/src/group_impl.h +++ b/src/group_impl.h @@ -73,35 +73,78 @@ static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_G; #endif /* End of section generated by sage/gen_exhaustive_groups.sage. */ +#ifdef VERIFY +static void secp256k1_ge_verify(const secp256k1_ge *a) { + secp256k1_fe_verify(&a->x); + secp256k1_fe_verify(&a->y); + VERIFY_CHECK(a->infinity == 0 || a->infinity == 1); +} + +static void secp256k1_gej_verify(const secp256k1_gej *a) { + secp256k1_fe_verify(&a->x); + secp256k1_fe_verify(&a->y); + secp256k1_fe_verify(&a->z); + VERIFY_CHECK(a->infinity == 0 || a->infinity == 1); +} +#endif + static void secp256k1_ge_set_gej_zinv(secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zi) { secp256k1_fe zi2; secp256k1_fe zi3; +#ifdef VERIFY + /* Do not call secp256k1_ge_verify, as we do not require a->z to be initialized. */ + secp256k1_fe_verify(&a->x); + secp256k1_fe_verify(&a->y); + secp256k1_fe_verify(zi); +#endif VERIFY_CHECK(!a->infinity); secp256k1_fe_sqr(&zi2, zi); secp256k1_fe_mul(&zi3, &zi2, zi); secp256k1_fe_mul(&r->x, &a->x, &zi2); secp256k1_fe_mul(&r->y, &a->y, &zi3); r->infinity = a->infinity; +#ifdef VERIFY + secp256k1_ge_verify(r); +#endif } static void secp256k1_ge_set_xy(secp256k1_ge *r, const secp256k1_fe *x, const secp256k1_fe *y) { +#ifdef VERIFY + secp256k1_fe_verify(x); + secp256k1_fe_verify(y); +#endif r->infinity = 0; r->x = *x; r->y = *y; +#ifdef VERIFY + secp256k1_ge_verify(r); +#endif } static int secp256k1_ge_is_infinity(const secp256k1_ge *a) { +#ifdef VERIFY + secp256k1_ge_verify(a); +#endif return a->infinity; } static void secp256k1_ge_neg(secp256k1_ge *r, const secp256k1_ge *a) { +#ifdef VERIFY + secp256k1_ge_verify(a); +#endif *r = *a; secp256k1_fe_normalize_weak(&r->y); secp256k1_fe_negate(&r->y, &r->y, 1); +#ifdef VERIFY + secp256k1_ge_verify(r); +#endif } static void secp256k1_ge_set_gej(secp256k1_ge *r, secp256k1_gej *a) { secp256k1_fe z2, z3; +#ifdef VERIFY + secp256k1_gej_verify(a); +#endif r->infinity = a->infinity; secp256k1_fe_inv(&a->z, &a->z); secp256k1_fe_sqr(&z2, &a->z); @@ -111,10 +154,16 @@ static void secp256k1_ge_set_gej(secp256k1_ge *r, secp256k1_gej *a) { secp256k1_fe_set_int(&a->z, 1); r->x = a->x; r->y = a->y; +#ifdef VERIFY + secp256k1_ge_verify(r); +#endif } static void secp256k1_ge_set_gej_var(secp256k1_ge *r, secp256k1_gej *a) { secp256k1_fe z2, z3; +#ifdef VERIFY + secp256k1_gej_verify(a); +#endif if (secp256k1_gej_is_infinity(a)) { secp256k1_ge_set_infinity(r); return; @@ -127,6 +176,9 @@ static void secp256k1_ge_set_gej_var(secp256k1_ge *r, secp256k1_gej *a) { secp256k1_fe_mul(&a->y, &a->y, &z3); secp256k1_fe_set_int(&a->z, 1); secp256k1_ge_set_xy(r, &a->x, &a->y); +#ifdef VERIFY + secp256k1_ge_verify(r); +#endif } static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a, size_t len) { @@ -135,6 +187,9 @@ static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a size_t last_i = SIZE_MAX; for (i = 0; i < len; i++) { +#ifdef VERIFY + secp256k1_gej_verify(&a[i]); +#endif if (a[i].infinity) { secp256k1_ge_set_infinity(&r[i]); } else { @@ -168,6 +223,9 @@ static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a if (!a[i].infinity) { secp256k1_ge_set_gej_zinv(&r[i], &a[i], &r[i].x); } +#ifdef VERIFY + secp256k1_ge_verify(&r[i]); +#endif } } @@ -176,6 +234,11 @@ static void secp256k1_ge_table_set_globalz(size_t len, secp256k1_ge *a, const se secp256k1_fe zs; if (len > 0) { +#ifdef VERIFY + /* Verify inputs a[len-1] and zr[len-1]. */ + secp256k1_ge_verify(&a[i]); + secp256k1_fe_verify(&zr[i]); +#endif /* Ensure all y values are in weak normal form for fast negation of points */ secp256k1_fe_normalize_weak(&a[i].y); zs = zr[i]; @@ -183,6 +246,11 @@ static void secp256k1_ge_table_set_globalz(size_t len, secp256k1_ge *a, const se /* Work our way backwards, using the z-ratios to scale the x/y values. */ while (i > 0) { secp256k1_gej tmpa; +#ifdef VERIFY + /* Verify all inputs a[i] and zr[i]. */ + secp256k1_fe_verify(&zr[i]); + secp256k1_ge_verify(&a[i]); +#endif if (i != len - 1) { secp256k1_fe_mul(&zs, &zs, &zr[i]); } @@ -191,6 +259,10 @@ static void secp256k1_ge_table_set_globalz(size_t len, secp256k1_ge *a, const se tmpa.y = a[i].y; tmpa.infinity = 0; secp256k1_ge_set_gej_zinv(&a[i], &tmpa, &zs); +#ifdef VERIFY + /* Verify the output a[i]. */ + secp256k1_ge_verify(&a[i]); +#endif } } } @@ -200,12 +272,18 @@ static void secp256k1_gej_set_infinity(secp256k1_gej *r) { secp256k1_fe_clear(&r->x); secp256k1_fe_clear(&r->y); secp256k1_fe_clear(&r->z); +#ifdef VERIFY + secp256k1_gej_verify(r); +#endif } static void secp256k1_ge_set_infinity(secp256k1_ge *r) { r->infinity = 1; secp256k1_fe_clear(&r->x); secp256k1_fe_clear(&r->y); +#ifdef VERIFY + secp256k1_ge_verify(r); +#endif } static void secp256k1_gej_clear(secp256k1_gej *r) { @@ -223,31 +301,45 @@ static void secp256k1_ge_clear(secp256k1_ge *r) { static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int odd) { secp256k1_fe x2, x3; + int ret; +#ifdef VERIFY + secp256k1_fe_verify(x); +#endif r->x = *x; secp256k1_fe_sqr(&x2, x); secp256k1_fe_mul(&x3, x, &x2); r->infinity = 0; secp256k1_fe_add_int(&x3, SECP256K1_B); - if (!secp256k1_fe_sqrt(&r->y, &x3)) { - return 0; - } + ret = secp256k1_fe_sqrt(&r->y, &x3); secp256k1_fe_normalize_var(&r->y); if (secp256k1_fe_is_odd(&r->y) != odd) { secp256k1_fe_negate(&r->y, &r->y, 1); } - return 1; - +#ifdef VERIFY + secp256k1_ge_verify(r); +#endif + return ret; } static void secp256k1_gej_set_ge(secp256k1_gej *r, const secp256k1_ge *a) { +#ifdef VERIFY + secp256k1_ge_verify(a); +#endif r->infinity = a->infinity; r->x = a->x; r->y = a->y; secp256k1_fe_set_int(&r->z, 1); +#ifdef VERIFY + secp256k1_gej_verify(r); +#endif } static int secp256k1_gej_eq_var(const secp256k1_gej *a, const secp256k1_gej *b) { secp256k1_gej tmp; +#ifdef VERIFY + secp256k1_gej_verify(b); + secp256k1_gej_verify(a); +#endif secp256k1_gej_neg(&tmp, a); secp256k1_gej_add_var(&tmp, &tmp, b, NULL); return secp256k1_gej_is_infinity(&tmp); @@ -255,6 +347,10 @@ static int secp256k1_gej_eq_var(const secp256k1_gej *a, const secp256k1_gej *b) static int secp256k1_gej_eq_x_var(const secp256k1_fe *x, const secp256k1_gej *a) { secp256k1_fe r, r2; +#ifdef VERIFY + secp256k1_fe_verify(x); + secp256k1_gej_verify(a); +#endif VERIFY_CHECK(!a->infinity); secp256k1_fe_sqr(&r, &a->z); secp256k1_fe_mul(&r, &r, x); r2 = a->x; secp256k1_fe_normalize_weak(&r2); @@ -262,20 +358,32 @@ static int secp256k1_gej_eq_x_var(const secp256k1_fe *x, const secp256k1_gej *a) } static void secp256k1_gej_neg(secp256k1_gej *r, const secp256k1_gej *a) { +#ifdef VERIFY + secp256k1_gej_verify(a); +#endif r->infinity = a->infinity; r->x = a->x; r->y = a->y; r->z = a->z; secp256k1_fe_normalize_weak(&r->y); secp256k1_fe_negate(&r->y, &r->y, 1); +#ifdef VERIFY + secp256k1_gej_verify(r); +#endif } static int secp256k1_gej_is_infinity(const secp256k1_gej *a) { +#ifdef VERIFY + secp256k1_gej_verify(a); +#endif return a->infinity; } static int secp256k1_ge_is_valid_var(const secp256k1_ge *a) { secp256k1_fe y2, x3; +#ifdef VERIFY + secp256k1_ge_verify(a); +#endif if (a->infinity) { return 0; } @@ -291,6 +399,9 @@ static SECP256K1_INLINE void secp256k1_gej_double(secp256k1_gej *r, const secp25 /* Operations: 3 mul, 4 sqr, 8 add/half/mul_int/negate */ secp256k1_fe l, s, t; +#ifdef VERIFY + secp256k1_gej_verify(a); +#endif r->infinity = a->infinity; /* Formula used: @@ -317,6 +428,9 @@ static SECP256K1_INLINE void secp256k1_gej_double(secp256k1_gej *r, const secp25 secp256k1_fe_mul(&r->y, &t, &l); /* Y3 = L*(X3 + T) (1) */ secp256k1_fe_add(&r->y, &s); /* Y3 = L*(X3 + T) + S^2 (2) */ secp256k1_fe_negate(&r->y, &r->y, 2); /* Y3 = -(L*(X3 + T) + S^2) (3) */ +#ifdef VERIFY + secp256k1_gej_verify(r); +#endif } static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr) { @@ -330,6 +444,9 @@ static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, s * the infinity flag even though the point doubles to infinity, and the result * point will be gibberish (z = 0 but infinity = 0). */ +#ifdef VERIFY + secp256k1_gej_verify(a); +#endif if (a->infinity) { secp256k1_gej_set_infinity(r); if (rzr != NULL) { @@ -344,12 +461,19 @@ static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, s } secp256k1_gej_double(r, a); +#ifdef VERIFY + secp256k1_gej_verify(r); +#endif } static void secp256k1_gej_add_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_gej *b, secp256k1_fe *rzr) { /* 12 mul, 4 sqr, 11 add/negate/normalizes_to_zero (ignoring special cases) */ secp256k1_fe z22, z12, u1, u2, s1, s2, h, i, h2, h3, t; +#ifdef VERIFY + secp256k1_gej_verify(a); + secp256k1_gej_verify(b); +#endif if (a->infinity) { VERIFY_CHECK(rzr == NULL); *r = *b; @@ -404,11 +528,18 @@ static void secp256k1_gej_add_var(secp256k1_gej *r, const secp256k1_gej *a, cons secp256k1_fe_mul(&r->y, &t, &i); secp256k1_fe_mul(&h3, &h3, &s1); secp256k1_fe_add(&r->y, &h3); +#ifdef VERIFY + secp256k1_gej_verify(r); +#endif } static void secp256k1_gej_add_ge_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, secp256k1_fe *rzr) { /* 8 mul, 3 sqr, 13 add/negate/normalize_weak/normalizes_to_zero (ignoring special cases) */ secp256k1_fe z12, u1, u2, s1, s2, h, i, h2, h3, t; +#ifdef VERIFY + secp256k1_gej_verify(a); + secp256k1_ge_verify(b); +#endif if (a->infinity) { VERIFY_CHECK(rzr == NULL); secp256k1_gej_set_ge(r, b); @@ -461,12 +592,20 @@ static void secp256k1_gej_add_ge_var(secp256k1_gej *r, const secp256k1_gej *a, c secp256k1_fe_mul(&r->y, &t, &i); secp256k1_fe_mul(&h3, &h3, &s1); secp256k1_fe_add(&r->y, &h3); +#ifdef VERIFY + secp256k1_gej_verify(r); + if (rzr != NULL) secp256k1_fe_verify(rzr); +#endif } static void secp256k1_gej_add_zinv_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, const secp256k1_fe *bzinv) { /* 9 mul, 3 sqr, 13 add/negate/normalize_weak/normalizes_to_zero (ignoring special cases) */ secp256k1_fe az, z12, u1, u2, s1, s2, h, i, h2, h3, t; +#ifdef VERIFY + secp256k1_ge_verify(b); + secp256k1_fe_verify(bzinv); +#endif if (a->infinity) { secp256k1_fe bzinv2, bzinv3; r->infinity = b->infinity; @@ -525,6 +664,9 @@ static void secp256k1_gej_add_zinv_var(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe_mul(&r->y, &t, &i); secp256k1_fe_mul(&h3, &h3, &s1); secp256k1_fe_add(&r->y, &h3); +#ifdef VERIFY + secp256k1_gej_verify(r); +#endif } @@ -533,6 +675,10 @@ static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_fe zz, u1, u2, s1, s2, t, tt, m, n, q, rr; secp256k1_fe m_alt, rr_alt; int degenerate; +#ifdef VERIFY + secp256k1_gej_verify(a); + secp256k1_ge_verify(b); +#endif VERIFY_CHECK(!b->infinity); VERIFY_CHECK(a->infinity == 0 || a->infinity == 1); @@ -658,21 +804,34 @@ static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const * We have degenerate = false, r->z = (y1 + y2) * Z. * Then r->infinity = ((y1 + y2)Z == 0) = (y1 == -y2) = false. */ r->infinity = secp256k1_fe_normalizes_to_zero(&r->z); +#ifdef VERIFY + secp256k1_gej_verify(r); +#endif } static void secp256k1_gej_rescale(secp256k1_gej *r, const secp256k1_fe *s) { /* Operations: 4 mul, 1 sqr */ secp256k1_fe zz; +#ifdef VERIFY + secp256k1_gej_verify(r); + secp256k1_fe_verify(s); +#endif VERIFY_CHECK(!secp256k1_fe_is_zero(s)); secp256k1_fe_sqr(&zz, s); secp256k1_fe_mul(&r->x, &r->x, &zz); /* r->x *= s^2 */ secp256k1_fe_mul(&r->y, &r->y, &zz); secp256k1_fe_mul(&r->y, &r->y, s); /* r->y *= s^3 */ secp256k1_fe_mul(&r->z, &r->z, s); /* r->z *= s */ +#ifdef VERIFY + secp256k1_gej_verify(r); +#endif } static void secp256k1_ge_to_storage(secp256k1_ge_storage *r, const secp256k1_ge *a) { secp256k1_fe x, y; +#ifdef VERIFY + secp256k1_ge_verify(a); +#endif VERIFY_CHECK(!a->infinity); x = a->x; secp256k1_fe_normalize(&x); @@ -686,14 +845,24 @@ static void secp256k1_ge_from_storage(secp256k1_ge *r, const secp256k1_ge_storag secp256k1_fe_from_storage(&r->x, &a->x); secp256k1_fe_from_storage(&r->y, &a->y); r->infinity = 0; +#ifdef VERIFY + secp256k1_ge_verify(r); +#endif } static SECP256K1_INLINE void secp256k1_gej_cmov(secp256k1_gej *r, const secp256k1_gej *a, int flag) { +#ifdef VERIFY + secp256k1_gej_verify(r); + secp256k1_gej_verify(a); +#endif secp256k1_fe_cmov(&r->x, &a->x, flag); secp256k1_fe_cmov(&r->y, &a->y, flag); secp256k1_fe_cmov(&r->z, &a->z, flag); r->infinity ^= (r->infinity ^ a->infinity) & flag; +#ifdef VERIFY + secp256k1_gej_verify(r); +#endif } static SECP256K1_INLINE void secp256k1_ge_storage_cmov(secp256k1_ge_storage *r, const secp256k1_ge_storage *a, int flag) { @@ -703,7 +872,13 @@ static SECP256K1_INLINE void secp256k1_ge_storage_cmov(secp256k1_ge_storage *r, static void secp256k1_ge_mul_lambda(secp256k1_ge *r, const secp256k1_ge *a) { *r = *a; +#ifdef VERIFY + secp256k1_ge_verify(a); +#endif secp256k1_fe_mul(&r->x, &r->x, &secp256k1_const_beta); +#ifdef VERIFY + secp256k1_ge_verify(r); +#endif } static int secp256k1_ge_is_in_correct_subgroup(const secp256k1_ge* ge) { @@ -711,6 +886,9 @@ static int secp256k1_ge_is_in_correct_subgroup(const secp256k1_ge* ge) { secp256k1_gej out; int i; +#ifdef VERIFY + secp256k1_ge_verify(ge); +#endif /* A very simple EC multiplication ladder that avoids a dependency on ecmult. */ secp256k1_gej_set_infinity(&out); for (i = 0; i < 32; ++i) { From 0a2e0b2ae456c7ae60e92ddc354071f21fb6aa62 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Tue, 9 May 2023 12:46:00 -0400 Subject: [PATCH 050/100] Make secp256k1_{fe,ge,gej}_verify work as no-op if non-VERIFY --- src/field.h | 4 +- src/field_10x26_impl.h | 9 ++-- src/field_5x52_impl.h | 9 ++-- src/group.h | 6 +-- src/group_impl.h | 106 +++-------------------------------------- 5 files changed, 15 insertions(+), 119 deletions(-) diff --git a/src/field.h b/src/field.h index 62dc0f3ae0..dca75aac10 100644 --- a/src/field.h +++ b/src/field.h @@ -143,9 +143,7 @@ static void secp256k1_fe_get_bounds(secp256k1_fe *r, int m); /** Determine whether a is a square (modulo p). */ static int secp256k1_fe_is_square_var(const secp256k1_fe *a); -#ifdef VERIFY -/** Check invariants on a field element. */ +/** Check invariants on a field element (no-op unless VERIFY is enabled). */ static void secp256k1_fe_verify(const secp256k1_fe *a); -#endif #endif /* SECP256K1_FIELD_H */ diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h index 6b58380f98..c164711757 100644 --- a/src/field_10x26_impl.h +++ b/src/field_10x26_impl.h @@ -21,8 +21,8 @@ * - 2*M*(2^26-1) is the max (inclusive) of the remaining limbs */ -#ifdef VERIFY static void secp256k1_fe_verify(const secp256k1_fe *a) { +#ifdef VERIFY const uint32_t *d = a->n; int m = a->normalized ? 1 : 2 * a->magnitude, r = 1; r &= (d[0] <= 0x3FFFFFFUL * m); @@ -47,8 +47,9 @@ static void secp256k1_fe_verify(const secp256k1_fe *a) { } } VERIFY_CHECK(r == 1); -} #endif + (void)a; +} static void secp256k1_fe_get_bounds(secp256k1_fe *r, int m) { VERIFY_CHECK(m >= 0); @@ -458,9 +459,7 @@ SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe *r, int a) { } SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a) { -#ifdef VERIFY secp256k1_fe_verify(a); -#endif r->n[0] += a->n[0]; r->n[1] += a->n[1]; r->n[2] += a->n[2]; @@ -479,11 +478,9 @@ SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_f } SECP256K1_INLINE static void secp256k1_fe_add_int(secp256k1_fe *r, int a) { -#ifdef VERIFY secp256k1_fe_verify(r); VERIFY_CHECK(a >= 0); VERIFY_CHECK(a <= 0x7FFF); -#endif r->n[0] += a; #ifdef VERIFY r->magnitude += 1; diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h index 0e403f32a6..9b9794c099 100644 --- a/src/field_5x52_impl.h +++ b/src/field_5x52_impl.h @@ -33,8 +33,8 @@ * 0 or 1, and its value is already reduced modulo the order of the field. */ -#ifdef VERIFY static void secp256k1_fe_verify(const secp256k1_fe *a) { +#ifdef VERIFY const uint64_t *d = a->n; int m = a->normalized ? 1 : 2 * a->magnitude, r = 1; /* secp256k1 'p' value defined in "Standards for Efficient Cryptography" (SEC2) 2.7.1. */ @@ -52,8 +52,9 @@ static void secp256k1_fe_verify(const secp256k1_fe *a) { } } VERIFY_CHECK(r == 1); -} #endif + (void)a; +} static void secp256k1_fe_get_bounds(secp256k1_fe *r, int m) { VERIFY_CHECK(m >= 0); @@ -422,11 +423,9 @@ SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe *r, int a) { } SECP256K1_INLINE static void secp256k1_fe_add_int(secp256k1_fe *r, int a) { -#ifdef VERIFY secp256k1_fe_verify(r); VERIFY_CHECK(a >= 0); VERIFY_CHECK(a <= 0x7FFF); -#endif r->n[0] += a; #ifdef VERIFY r->magnitude += 1; @@ -436,9 +435,7 @@ SECP256K1_INLINE static void secp256k1_fe_add_int(secp256k1_fe *r, int a) { } SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a) { -#ifdef VERIFY secp256k1_fe_verify(a); -#endif r->n[0] += a->n[0]; r->n[1] += a->n[1]; r->n[2] += a->n[2]; diff --git a/src/group.h b/src/group.h index 14cdb4062d..77ad7435f8 100644 --- a/src/group.h +++ b/src/group.h @@ -164,12 +164,10 @@ static void secp256k1_gej_rescale(secp256k1_gej *r, const secp256k1_fe *b); */ static int secp256k1_ge_is_in_correct_subgroup(const secp256k1_ge* ge); -#ifdef VERIFY -/** Check invariants on an affine group element. */ +/** Check invariants on an affine group element (no-op unless VERIFY is enabled). */ static void secp256k1_ge_verify(const secp256k1_ge *a); -/** Check invariants on a Jacobian group element. */ +/** Check invariants on a Jacobian group element (no-op unless VERIFY is enabled). */ static void secp256k1_gej_verify(const secp256k1_gej *a); -#endif #endif /* SECP256K1_GROUP_H */ diff --git a/src/group_impl.h b/src/group_impl.h index 86be92d59d..48357a1c5d 100644 --- a/src/group_impl.h +++ b/src/group_impl.h @@ -73,78 +73,66 @@ static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_G; #endif /* End of section generated by sage/gen_exhaustive_groups.sage. */ -#ifdef VERIFY static void secp256k1_ge_verify(const secp256k1_ge *a) { +#ifdef VERIFY secp256k1_fe_verify(&a->x); secp256k1_fe_verify(&a->y); VERIFY_CHECK(a->infinity == 0 || a->infinity == 1); +#endif + (void)a; } static void secp256k1_gej_verify(const secp256k1_gej *a) { +#ifdef VERIFY secp256k1_fe_verify(&a->x); secp256k1_fe_verify(&a->y); secp256k1_fe_verify(&a->z); VERIFY_CHECK(a->infinity == 0 || a->infinity == 1); -} #endif + (void)a; +} static void secp256k1_ge_set_gej_zinv(secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zi) { secp256k1_fe zi2; secp256k1_fe zi3; -#ifdef VERIFY /* Do not call secp256k1_ge_verify, as we do not require a->z to be initialized. */ secp256k1_fe_verify(&a->x); secp256k1_fe_verify(&a->y); secp256k1_fe_verify(zi); -#endif VERIFY_CHECK(!a->infinity); secp256k1_fe_sqr(&zi2, zi); secp256k1_fe_mul(&zi3, &zi2, zi); secp256k1_fe_mul(&r->x, &a->x, &zi2); secp256k1_fe_mul(&r->y, &a->y, &zi3); r->infinity = a->infinity; -#ifdef VERIFY secp256k1_ge_verify(r); -#endif } static void secp256k1_ge_set_xy(secp256k1_ge *r, const secp256k1_fe *x, const secp256k1_fe *y) { -#ifdef VERIFY secp256k1_fe_verify(x); secp256k1_fe_verify(y); -#endif r->infinity = 0; r->x = *x; r->y = *y; -#ifdef VERIFY secp256k1_ge_verify(r); -#endif } static int secp256k1_ge_is_infinity(const secp256k1_ge *a) { -#ifdef VERIFY secp256k1_ge_verify(a); -#endif return a->infinity; } static void secp256k1_ge_neg(secp256k1_ge *r, const secp256k1_ge *a) { -#ifdef VERIFY secp256k1_ge_verify(a); -#endif *r = *a; secp256k1_fe_normalize_weak(&r->y); secp256k1_fe_negate(&r->y, &r->y, 1); -#ifdef VERIFY secp256k1_ge_verify(r); -#endif } static void secp256k1_ge_set_gej(secp256k1_ge *r, secp256k1_gej *a) { secp256k1_fe z2, z3; -#ifdef VERIFY secp256k1_gej_verify(a); -#endif r->infinity = a->infinity; secp256k1_fe_inv(&a->z, &a->z); secp256k1_fe_sqr(&z2, &a->z); @@ -154,16 +142,12 @@ static void secp256k1_ge_set_gej(secp256k1_ge *r, secp256k1_gej *a) { secp256k1_fe_set_int(&a->z, 1); r->x = a->x; r->y = a->y; -#ifdef VERIFY secp256k1_ge_verify(r); -#endif } static void secp256k1_ge_set_gej_var(secp256k1_ge *r, secp256k1_gej *a) { secp256k1_fe z2, z3; -#ifdef VERIFY secp256k1_gej_verify(a); -#endif if (secp256k1_gej_is_infinity(a)) { secp256k1_ge_set_infinity(r); return; @@ -176,9 +160,7 @@ static void secp256k1_ge_set_gej_var(secp256k1_ge *r, secp256k1_gej *a) { secp256k1_fe_mul(&a->y, &a->y, &z3); secp256k1_fe_set_int(&a->z, 1); secp256k1_ge_set_xy(r, &a->x, &a->y); -#ifdef VERIFY secp256k1_ge_verify(r); -#endif } static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a, size_t len) { @@ -187,9 +169,7 @@ static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a size_t last_i = SIZE_MAX; for (i = 0; i < len; i++) { -#ifdef VERIFY secp256k1_gej_verify(&a[i]); -#endif if (a[i].infinity) { secp256k1_ge_set_infinity(&r[i]); } else { @@ -223,9 +203,7 @@ static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a if (!a[i].infinity) { secp256k1_ge_set_gej_zinv(&r[i], &a[i], &r[i].x); } -#ifdef VERIFY secp256k1_ge_verify(&r[i]); -#endif } } @@ -234,11 +212,9 @@ static void secp256k1_ge_table_set_globalz(size_t len, secp256k1_ge *a, const se secp256k1_fe zs; if (len > 0) { -#ifdef VERIFY /* Verify inputs a[len-1] and zr[len-1]. */ secp256k1_ge_verify(&a[i]); secp256k1_fe_verify(&zr[i]); -#endif /* Ensure all y values are in weak normal form for fast negation of points */ secp256k1_fe_normalize_weak(&a[i].y); zs = zr[i]; @@ -246,11 +222,9 @@ static void secp256k1_ge_table_set_globalz(size_t len, secp256k1_ge *a, const se /* Work our way backwards, using the z-ratios to scale the x/y values. */ while (i > 0) { secp256k1_gej tmpa; -#ifdef VERIFY /* Verify all inputs a[i] and zr[i]. */ secp256k1_fe_verify(&zr[i]); secp256k1_ge_verify(&a[i]); -#endif if (i != len - 1) { secp256k1_fe_mul(&zs, &zs, &zr[i]); } @@ -259,10 +233,8 @@ static void secp256k1_ge_table_set_globalz(size_t len, secp256k1_ge *a, const se tmpa.y = a[i].y; tmpa.infinity = 0; secp256k1_ge_set_gej_zinv(&a[i], &tmpa, &zs); -#ifdef VERIFY /* Verify the output a[i]. */ secp256k1_ge_verify(&a[i]); -#endif } } } @@ -272,18 +244,14 @@ static void secp256k1_gej_set_infinity(secp256k1_gej *r) { secp256k1_fe_clear(&r->x); secp256k1_fe_clear(&r->y); secp256k1_fe_clear(&r->z); -#ifdef VERIFY secp256k1_gej_verify(r); -#endif } static void secp256k1_ge_set_infinity(secp256k1_ge *r) { r->infinity = 1; secp256k1_fe_clear(&r->x); secp256k1_fe_clear(&r->y); -#ifdef VERIFY secp256k1_ge_verify(r); -#endif } static void secp256k1_gej_clear(secp256k1_gej *r) { @@ -302,9 +270,7 @@ static void secp256k1_ge_clear(secp256k1_ge *r) { static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int odd) { secp256k1_fe x2, x3; int ret; -#ifdef VERIFY secp256k1_fe_verify(x); -#endif r->x = *x; secp256k1_fe_sqr(&x2, x); secp256k1_fe_mul(&x3, x, &x2); @@ -315,31 +281,23 @@ static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int o if (secp256k1_fe_is_odd(&r->y) != odd) { secp256k1_fe_negate(&r->y, &r->y, 1); } -#ifdef VERIFY secp256k1_ge_verify(r); -#endif return ret; } static void secp256k1_gej_set_ge(secp256k1_gej *r, const secp256k1_ge *a) { -#ifdef VERIFY secp256k1_ge_verify(a); -#endif r->infinity = a->infinity; r->x = a->x; r->y = a->y; secp256k1_fe_set_int(&r->z, 1); -#ifdef VERIFY secp256k1_gej_verify(r); -#endif } static int secp256k1_gej_eq_var(const secp256k1_gej *a, const secp256k1_gej *b) { secp256k1_gej tmp; -#ifdef VERIFY secp256k1_gej_verify(b); secp256k1_gej_verify(a); -#endif secp256k1_gej_neg(&tmp, a); secp256k1_gej_add_var(&tmp, &tmp, b, NULL); return secp256k1_gej_is_infinity(&tmp); @@ -347,10 +305,8 @@ static int secp256k1_gej_eq_var(const secp256k1_gej *a, const secp256k1_gej *b) static int secp256k1_gej_eq_x_var(const secp256k1_fe *x, const secp256k1_gej *a) { secp256k1_fe r, r2; -#ifdef VERIFY secp256k1_fe_verify(x); secp256k1_gej_verify(a); -#endif VERIFY_CHECK(!a->infinity); secp256k1_fe_sqr(&r, &a->z); secp256k1_fe_mul(&r, &r, x); r2 = a->x; secp256k1_fe_normalize_weak(&r2); @@ -358,32 +314,24 @@ static int secp256k1_gej_eq_x_var(const secp256k1_fe *x, const secp256k1_gej *a) } static void secp256k1_gej_neg(secp256k1_gej *r, const secp256k1_gej *a) { -#ifdef VERIFY secp256k1_gej_verify(a); -#endif r->infinity = a->infinity; r->x = a->x; r->y = a->y; r->z = a->z; secp256k1_fe_normalize_weak(&r->y); secp256k1_fe_negate(&r->y, &r->y, 1); -#ifdef VERIFY secp256k1_gej_verify(r); -#endif } static int secp256k1_gej_is_infinity(const secp256k1_gej *a) { -#ifdef VERIFY secp256k1_gej_verify(a); -#endif return a->infinity; } static int secp256k1_ge_is_valid_var(const secp256k1_ge *a) { secp256k1_fe y2, x3; -#ifdef VERIFY secp256k1_ge_verify(a); -#endif if (a->infinity) { return 0; } @@ -399,9 +347,7 @@ static SECP256K1_INLINE void secp256k1_gej_double(secp256k1_gej *r, const secp25 /* Operations: 3 mul, 4 sqr, 8 add/half/mul_int/negate */ secp256k1_fe l, s, t; -#ifdef VERIFY secp256k1_gej_verify(a); -#endif r->infinity = a->infinity; /* Formula used: @@ -428,9 +374,7 @@ static SECP256K1_INLINE void secp256k1_gej_double(secp256k1_gej *r, const secp25 secp256k1_fe_mul(&r->y, &t, &l); /* Y3 = L*(X3 + T) (1) */ secp256k1_fe_add(&r->y, &s); /* Y3 = L*(X3 + T) + S^2 (2) */ secp256k1_fe_negate(&r->y, &r->y, 2); /* Y3 = -(L*(X3 + T) + S^2) (3) */ -#ifdef VERIFY secp256k1_gej_verify(r); -#endif } static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr) { @@ -444,9 +388,7 @@ static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, s * the infinity flag even though the point doubles to infinity, and the result * point will be gibberish (z = 0 but infinity = 0). */ -#ifdef VERIFY secp256k1_gej_verify(a); -#endif if (a->infinity) { secp256k1_gej_set_infinity(r); if (rzr != NULL) { @@ -461,19 +403,15 @@ static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, s } secp256k1_gej_double(r, a); -#ifdef VERIFY secp256k1_gej_verify(r); -#endif } static void secp256k1_gej_add_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_gej *b, secp256k1_fe *rzr) { /* 12 mul, 4 sqr, 11 add/negate/normalizes_to_zero (ignoring special cases) */ secp256k1_fe z22, z12, u1, u2, s1, s2, h, i, h2, h3, t; -#ifdef VERIFY secp256k1_gej_verify(a); secp256k1_gej_verify(b); -#endif if (a->infinity) { VERIFY_CHECK(rzr == NULL); *r = *b; @@ -528,18 +466,14 @@ static void secp256k1_gej_add_var(secp256k1_gej *r, const secp256k1_gej *a, cons secp256k1_fe_mul(&r->y, &t, &i); secp256k1_fe_mul(&h3, &h3, &s1); secp256k1_fe_add(&r->y, &h3); -#ifdef VERIFY secp256k1_gej_verify(r); -#endif } static void secp256k1_gej_add_ge_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, secp256k1_fe *rzr) { /* 8 mul, 3 sqr, 13 add/negate/normalize_weak/normalizes_to_zero (ignoring special cases) */ secp256k1_fe z12, u1, u2, s1, s2, h, i, h2, h3, t; -#ifdef VERIFY secp256k1_gej_verify(a); secp256k1_ge_verify(b); -#endif if (a->infinity) { VERIFY_CHECK(rzr == NULL); secp256k1_gej_set_ge(r, b); @@ -592,20 +526,16 @@ static void secp256k1_gej_add_ge_var(secp256k1_gej *r, const secp256k1_gej *a, c secp256k1_fe_mul(&r->y, &t, &i); secp256k1_fe_mul(&h3, &h3, &s1); secp256k1_fe_add(&r->y, &h3); -#ifdef VERIFY secp256k1_gej_verify(r); if (rzr != NULL) secp256k1_fe_verify(rzr); -#endif } static void secp256k1_gej_add_zinv_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, const secp256k1_fe *bzinv) { /* 9 mul, 3 sqr, 13 add/negate/normalize_weak/normalizes_to_zero (ignoring special cases) */ secp256k1_fe az, z12, u1, u2, s1, s2, h, i, h2, h3, t; -#ifdef VERIFY secp256k1_ge_verify(b); secp256k1_fe_verify(bzinv); -#endif if (a->infinity) { secp256k1_fe bzinv2, bzinv3; r->infinity = b->infinity; @@ -664,9 +594,7 @@ static void secp256k1_gej_add_zinv_var(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe_mul(&r->y, &t, &i); secp256k1_fe_mul(&h3, &h3, &s1); secp256k1_fe_add(&r->y, &h3); -#ifdef VERIFY secp256k1_gej_verify(r); -#endif } @@ -675,10 +603,8 @@ static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_fe zz, u1, u2, s1, s2, t, tt, m, n, q, rr; secp256k1_fe m_alt, rr_alt; int degenerate; -#ifdef VERIFY secp256k1_gej_verify(a); secp256k1_ge_verify(b); -#endif VERIFY_CHECK(!b->infinity); VERIFY_CHECK(a->infinity == 0 || a->infinity == 1); @@ -804,34 +730,26 @@ static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const * We have degenerate = false, r->z = (y1 + y2) * Z. * Then r->infinity = ((y1 + y2)Z == 0) = (y1 == -y2) = false. */ r->infinity = secp256k1_fe_normalizes_to_zero(&r->z); -#ifdef VERIFY secp256k1_gej_verify(r); -#endif } static void secp256k1_gej_rescale(secp256k1_gej *r, const secp256k1_fe *s) { /* Operations: 4 mul, 1 sqr */ secp256k1_fe zz; -#ifdef VERIFY secp256k1_gej_verify(r); secp256k1_fe_verify(s); -#endif VERIFY_CHECK(!secp256k1_fe_is_zero(s)); secp256k1_fe_sqr(&zz, s); secp256k1_fe_mul(&r->x, &r->x, &zz); /* r->x *= s^2 */ secp256k1_fe_mul(&r->y, &r->y, &zz); secp256k1_fe_mul(&r->y, &r->y, s); /* r->y *= s^3 */ secp256k1_fe_mul(&r->z, &r->z, s); /* r->z *= s */ -#ifdef VERIFY secp256k1_gej_verify(r); -#endif } static void secp256k1_ge_to_storage(secp256k1_ge_storage *r, const secp256k1_ge *a) { secp256k1_fe x, y; -#ifdef VERIFY secp256k1_ge_verify(a); -#endif VERIFY_CHECK(!a->infinity); x = a->x; secp256k1_fe_normalize(&x); @@ -845,24 +763,18 @@ static void secp256k1_ge_from_storage(secp256k1_ge *r, const secp256k1_ge_storag secp256k1_fe_from_storage(&r->x, &a->x); secp256k1_fe_from_storage(&r->y, &a->y); r->infinity = 0; -#ifdef VERIFY secp256k1_ge_verify(r); -#endif } static SECP256K1_INLINE void secp256k1_gej_cmov(secp256k1_gej *r, const secp256k1_gej *a, int flag) { -#ifdef VERIFY secp256k1_gej_verify(r); secp256k1_gej_verify(a); -#endif secp256k1_fe_cmov(&r->x, &a->x, flag); secp256k1_fe_cmov(&r->y, &a->y, flag); secp256k1_fe_cmov(&r->z, &a->z, flag); r->infinity ^= (r->infinity ^ a->infinity) & flag; -#ifdef VERIFY secp256k1_gej_verify(r); -#endif } static SECP256K1_INLINE void secp256k1_ge_storage_cmov(secp256k1_ge_storage *r, const secp256k1_ge_storage *a, int flag) { @@ -872,13 +784,9 @@ static SECP256K1_INLINE void secp256k1_ge_storage_cmov(secp256k1_ge_storage *r, static void secp256k1_ge_mul_lambda(secp256k1_ge *r, const secp256k1_ge *a) { *r = *a; -#ifdef VERIFY secp256k1_ge_verify(a); -#endif secp256k1_fe_mul(&r->x, &r->x, &secp256k1_const_beta); -#ifdef VERIFY secp256k1_ge_verify(r); -#endif } static int secp256k1_ge_is_in_correct_subgroup(const secp256k1_ge* ge) { @@ -886,9 +794,7 @@ static int secp256k1_ge_is_in_correct_subgroup(const secp256k1_ge* ge) { secp256k1_gej out; int i; -#ifdef VERIFY secp256k1_ge_verify(ge); -#endif /* A very simple EC multiplication ladder that avoids a dependency on ecmult. */ secp256k1_gej_set_infinity(&out); for (i = 0; i < 32; ++i) { From bbc834467c5d14e3e53744211e7c4fa9d8fabe41 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Tue, 9 May 2023 13:10:56 -0400 Subject: [PATCH 051/100] Avoid secp256k1_ge_set_gej_zinv with uninitialized z --- src/group_impl.h | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/src/group_impl.h b/src/group_impl.h index 48357a1c5d..f1b62e3689 100644 --- a/src/group_impl.h +++ b/src/group_impl.h @@ -92,12 +92,26 @@ static void secp256k1_gej_verify(const secp256k1_gej *a) { (void)a; } +/* Set r to the affine coordinates of Jacobian point (a.x, a.y, 1/zi). */ static void secp256k1_ge_set_gej_zinv(secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zi) { secp256k1_fe zi2; secp256k1_fe zi3; - /* Do not call secp256k1_ge_verify, as we do not require a->z to be initialized. */ - secp256k1_fe_verify(&a->x); - secp256k1_fe_verify(&a->y); + secp256k1_gej_verify(a); + secp256k1_fe_verify(zi); + VERIFY_CHECK(!a->infinity); + secp256k1_fe_sqr(&zi2, zi); + secp256k1_fe_mul(&zi3, &zi2, zi); + secp256k1_fe_mul(&r->x, &a->x, &zi2); + secp256k1_fe_mul(&r->y, &a->y, &zi3); + r->infinity = a->infinity; + secp256k1_ge_verify(r); +} + +/* Set r to the affine coordinates of Jacobian point (a.x, a.y, 1/zi). */ +static void secp256k1_ge_set_ge_zinv(secp256k1_ge *r, const secp256k1_ge *a, const secp256k1_fe *zi) { + secp256k1_fe zi2; + secp256k1_fe zi3; + secp256k1_ge_verify(a); secp256k1_fe_verify(zi); VERIFY_CHECK(!a->infinity); secp256k1_fe_sqr(&zi2, zi); @@ -221,7 +235,6 @@ static void secp256k1_ge_table_set_globalz(size_t len, secp256k1_ge *a, const se /* Work our way backwards, using the z-ratios to scale the x/y values. */ while (i > 0) { - secp256k1_gej tmpa; /* Verify all inputs a[i] and zr[i]. */ secp256k1_fe_verify(&zr[i]); secp256k1_ge_verify(&a[i]); @@ -229,10 +242,7 @@ static void secp256k1_ge_table_set_globalz(size_t len, secp256k1_ge *a, const se secp256k1_fe_mul(&zs, &zs, &zr[i]); } i--; - tmpa.x = a[i].x; - tmpa.y = a[i].y; - tmpa.infinity = 0; - secp256k1_ge_set_gej_zinv(&a[i], &tmpa, &zs); + secp256k1_ge_set_ge_zinv(&a[i], &a[i], &zs); /* Verify the output a[i]. */ secp256k1_ge_verify(&a[i]); } From 97c63b90390b0b11a5d3530b03855ec9cc0de343 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Tue, 9 May 2023 13:52:16 -0400 Subject: [PATCH 052/100] Avoid normalize conditional on VERIFY --- src/ecmult_impl.h | 3 --- src/group_impl.h | 4 +++- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/ecmult_impl.h b/src/ecmult_impl.h index a9a63850ef..6f0152a879 100644 --- a/src/ecmult_impl.h +++ b/src/ecmult_impl.h @@ -279,9 +279,6 @@ static void secp256k1_ecmult_strauss_wnaf(const struct secp256k1_strauss_state * */ tmp = a[np]; if (no) { -#ifdef VERIFY - secp256k1_fe_normalize_var(&Z); -#endif secp256k1_gej_rescale(&tmp, &Z); } secp256k1_ecmult_odd_multiples_table(ECMULT_TABLE_SIZE(WINDOW_A), state->pre_a + no * ECMULT_TABLE_SIZE(WINDOW_A), state->aux + no * ECMULT_TABLE_SIZE(WINDOW_A), &Z, &tmp); diff --git a/src/group_impl.h b/src/group_impl.h index f1b62e3689..44d98434ca 100644 --- a/src/group_impl.h +++ b/src/group_impl.h @@ -748,7 +748,9 @@ static void secp256k1_gej_rescale(secp256k1_gej *r, const secp256k1_fe *s) { secp256k1_fe zz; secp256k1_gej_verify(r); secp256k1_fe_verify(s); - VERIFY_CHECK(!secp256k1_fe_is_zero(s)); +#ifdef VERIFY + VERIFY_CHECK(!secp256k1_fe_normalizes_to_zero_var(s)); +#endif secp256k1_fe_sqr(&zz, s); secp256k1_fe_mul(&r->x, &r->x, &zz); /* r->x *= s^2 */ secp256k1_fe_mul(&r->y, &r->y, &zz); From b29566c51b2a47139d610bf686e09ae9f9d24001 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 28 Jan 2022 17:39:30 -0500 Subject: [PATCH 053/100] Merge magnitude/normalized fields, move/improve comments Also split secp256k1_fe_verify into a generic and an implementation specific part. --- src/field.h | 45 +++++++++++++++++++++++++++++++----------- src/field_10x26.h | 27 ++++++++++++++++++------- src/field_10x26_impl.h | 17 ++-------------- src/field_5x52.h | 27 ++++++++++++++++++------- src/field_5x52_impl.h | 23 ++------------------- src/field_impl.h | 18 +++++++++++++++++ 6 files changed, 96 insertions(+), 61 deletions(-) diff --git a/src/field.h b/src/field.h index dca75aac10..28ebe85ac1 100644 --- a/src/field.h +++ b/src/field.h @@ -7,19 +7,36 @@ #ifndef SECP256K1_FIELD_H #define SECP256K1_FIELD_H -/** Field element module. - * - * Field elements can be represented in several ways, but code accessing - * it (and implementations) need to take certain properties into account: - * - Each field element can be normalized or not. - * - Each field element has a magnitude, which represents how far away - * its representation is away from normalization. Normalized elements - * always have a magnitude of 0 or 1, but a magnitude of 1 doesn't - * imply normality. - */ - #include "util.h" +/* This file defines the generic interface for working with secp256k1_fe + * objects, which represent field elements (integers modulo 2^256 - 2^32 - 977). + * + * The actual definition of the secp256k1_fe type depends on the chosen field + * implementation; see the field_5x52.h and field_10x26.h files for details. + * + * All secp256k1_fe objects have implicit properties that determine what + * operations are permitted on it. These are purely a function of what + * secp256k1_fe_ operations are applied on it, generally (implicitly) fixed at + * compile time, and do not depend on the chosen field implementation. Despite + * that, what these properties actually entail for the field representation + * values depends on the chosen field implementation. These properties are: + * - magnitude: an integer in [0,32] + * - normalized: 0 or 1; normalized=1 implies magnitude <= 1. + * + * In VERIFY mode, they are materialized explicitly as fields in the struct, + * allowing run-time verification of these properties. In that case, the field + * implementation also provides a secp256k1_fe_verify routine to verify that + * these fields match the run-time value and perform internal consistency + * checks. */ +#ifdef VERIFY +# define SECP256K1_FE_VERIFY_FIELDS \ + int magnitude; \ + int normalized; +#else +# define SECP256K1_FE_VERIFY_FIELDS +#endif + #if defined(SECP256K1_WIDEMUL_INT128) #include "field_5x52.h" #elif defined(SECP256K1_WIDEMUL_INT64) @@ -34,6 +51,12 @@ static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST( 0x9cf04975ul, 0x12f58995ul, 0xc1396c28ul, 0x719501eeul ); +#ifndef VERIFY +/* In non-VERIFY mode, we #define the fe operations to be identical to their + * internal field implementation, to avoid the potential overhead of a + * function call (even though presumably inlinable). */ +#endif /* !defined(VERIFY) */ + /** Normalize a field element. This brings the field element to a canonical representation, reduces * its magnitude to 1, and reduces it modulo field size `p`. */ diff --git a/src/field_10x26.h b/src/field_10x26.h index 9eb65607f1..4fe36d08e2 100644 --- a/src/field_10x26.h +++ b/src/field_10x26.h @@ -9,15 +9,28 @@ #include +/** This field implementation represents the value as 10 uint32_t limbs in base + * 2^26. */ typedef struct { - /* X = sum(i=0..9, n[i]*2^(i*26)) mod p - * where p = 2^256 - 0x1000003D1 - */ + /* A field element f represents the sum(i=0..9, f.n[i] << (i*26)) mod p, + * where p is the field modulus, 2^256 - 2^32 - 977. + * + * The individual limbs f.n[i] can exceed 2^26; the field's magnitude roughly + * corresponds to how much excess is allowed. The value + * sum(i=0..9, f.n[i] << (i*26)) may exceed p, unless the field element is + * normalized. */ uint32_t n[10]; -#ifdef VERIFY - int magnitude; - int normalized; -#endif + /* + * Magnitude m requires: + * n[i] <= 2 * m * (2^26 - 1) for i=0..8 + * n[9] <= 2 * m * (2^22 - 1) + * + * Normalized requires: + * n[i] <= (2^26 - 1) for i=0..8 + * sum(i=0..9, n[i] << (i*26)) < p + * (together these imply n[9] <= 2^22 - 1) + */ + SECP256K1_FE_VERIFY_FIELDS } secp256k1_fe; /* Unpacks a constant into a overlapping multi-limbed FE element. */ diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h index c164711757..8115f534ad 100644 --- a/src/field_10x26_impl.h +++ b/src/field_10x26_impl.h @@ -12,17 +12,8 @@ #include "field.h" #include "modinv32_impl.h" -/** See the comment at the top of field_5x52_impl.h for more details. - * - * Here, we represent field elements as 10 uint32_t's in base 2^26, least significant first, - * where limbs can contain >26 bits. - * A magnitude M means: - * - 2*M*(2^22-1) is the max (inclusive) of the most significant limb - * - 2*M*(2^26-1) is the max (inclusive) of the remaining limbs - */ - -static void secp256k1_fe_verify(const secp256k1_fe *a) { #ifdef VERIFY +static void secp256k1_fe_impl_verify(const secp256k1_fe *a) { const uint32_t *d = a->n; int m = a->normalized ? 1 : 2 * a->magnitude, r = 1; r &= (d[0] <= 0x3FFFFFFUL * m); @@ -35,10 +26,7 @@ static void secp256k1_fe_verify(const secp256k1_fe *a) { r &= (d[7] <= 0x3FFFFFFUL * m); r &= (d[8] <= 0x3FFFFFFUL * m); r &= (d[9] <= 0x03FFFFFUL * m); - r &= (a->magnitude >= 0); - r &= (a->magnitude <= 32); if (a->normalized) { - r &= (a->magnitude <= 1); if (r && (d[9] == 0x03FFFFFUL)) { uint32_t mid = d[8] & d[7] & d[6] & d[5] & d[4] & d[3] & d[2]; if (mid == 0x3FFFFFFUL) { @@ -47,9 +35,8 @@ static void secp256k1_fe_verify(const secp256k1_fe *a) { } } VERIFY_CHECK(r == 1); -#endif - (void)a; } +#endif static void secp256k1_fe_get_bounds(secp256k1_fe *r, int m) { VERIFY_CHECK(m >= 0); diff --git a/src/field_5x52.h b/src/field_5x52.h index 50ee3f9ec9..e4646a56be 100644 --- a/src/field_5x52.h +++ b/src/field_5x52.h @@ -9,15 +9,28 @@ #include +/** This field implementation represents the value as 5 uint64_t limbs in base + * 2^52. */ typedef struct { - /* X = sum(i=0..4, n[i]*2^(i*52)) mod p - * where p = 2^256 - 0x1000003D1 - */ + /* A field element f represents the sum(i=0..4, f.n[i] << (i*52)) mod p, + * where p is the field modulus, 2^256 - 2^32 - 977. + * + * The individual limbs f.n[i] can exceed 2^52; the field's magnitude roughly + * corresponds to how much excess is allowed. The value + * sum(i=0..4, f.n[i] << (i*52)) may exceed p, unless the field element is + * normalized. */ uint64_t n[5]; -#ifdef VERIFY - int magnitude; - int normalized; -#endif + /* + * Magnitude m requires: + * n[i] <= 2 * m * (2^52 - 1) for i=0..3 + * n[4] <= 2 * m * (2^48 - 1) + * + * Normalized requires: + * n[i] <= (2^52 - 1) for i=0..3 + * sum(i=0..4, n[i] << (i*52)) < p + * (together these imply n[4] <= 2^48 - 1) + */ + SECP256K1_FE_VERIFY_FIELDS } secp256k1_fe; /* Unpacks a constant into a overlapping multi-limbed FE element. */ diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h index 9b9794c099..cd240577f7 100644 --- a/src/field_5x52_impl.h +++ b/src/field_5x52_impl.h @@ -18,23 +18,8 @@ #include "field_5x52_int128_impl.h" #endif -/** Implements arithmetic modulo FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFFC2F, - * represented as 5 uint64_t's in base 2^52, least significant first. Note that the limbs are allowed to - * contain >52 bits each. - * - * Each field element has a 'magnitude' associated with it. Internally, a magnitude M means: - * - 2*M*(2^48-1) is the max (inclusive) of the most significant limb - * - 2*M*(2^52-1) is the max (inclusive) of the remaining limbs - * - * Operations have different rules for propagating magnitude to their outputs. If an operation takes a - * magnitude M as a parameter, that means the magnitude of input field elements can be at most M (inclusive). - * - * Each field element also has a 'normalized' flag. A field element is normalized if its magnitude is either - * 0 or 1, and its value is already reduced modulo the order of the field. - */ - -static void secp256k1_fe_verify(const secp256k1_fe *a) { #ifdef VERIFY +static void secp256k1_fe_impl_verify(const secp256k1_fe *a) { const uint64_t *d = a->n; int m = a->normalized ? 1 : 2 * a->magnitude, r = 1; /* secp256k1 'p' value defined in "Standards for Efficient Cryptography" (SEC2) 2.7.1. */ @@ -43,18 +28,14 @@ static void secp256k1_fe_verify(const secp256k1_fe *a) { r &= (d[2] <= 0xFFFFFFFFFFFFFULL * m); r &= (d[3] <= 0xFFFFFFFFFFFFFULL * m); r &= (d[4] <= 0x0FFFFFFFFFFFFULL * m); - r &= (a->magnitude >= 0); - r &= (a->magnitude <= 2048); if (a->normalized) { - r &= (a->magnitude <= 1); if (r && (d[4] == 0x0FFFFFFFFFFFFULL) && ((d[3] & d[2] & d[1]) == 0xFFFFFFFFFFFFFULL)) { r &= (d[0] < 0xFFFFEFFFFFC2FULL); } } VERIFY_CHECK(r == 1); -#endif - (void)a; } +#endif static void secp256k1_fe_get_bounds(secp256k1_fe *r, int m) { VERIFY_CHECK(m >= 0); diff --git a/src/field_impl.h b/src/field_impl.h index 0a03076bbc..9920dfdb78 100644 --- a/src/field_impl.h +++ b/src/field_impl.h @@ -7,6 +7,7 @@ #ifndef SECP256K1_FIELD_IMPL_H #define SECP256K1_FIELD_IMPL_H +#include "field.h" #include "util.h" #if defined(SECP256K1_WIDEMUL_INT128) @@ -131,4 +132,21 @@ static int secp256k1_fe_sqrt(secp256k1_fe *r, const secp256k1_fe *a) { return secp256k1_fe_equal(&t1, a); } +#ifndef VERIFY +static void secp256k1_fe_verify(const secp256k1_fe *a) { (void)a; } +#else +static void secp256k1_fe_impl_verify(const secp256k1_fe *a); +static void secp256k1_fe_verify(const secp256k1_fe *a) { + /* Magnitude between 0 and 32. */ + int r = (a->magnitude >= 0) & (a->magnitude <= 32); + /* Normalized is 0 or 1. */ + r &= (a->normalized == 0) | (a->normalized == 1); + /* If normalized, magnitude must be 0 or 1. */ + if (a->normalized) r &= (a->magnitude <= 1); + VERIFY_CHECK(r == 1); + /* Invoke implementation-specific checks. */ + secp256k1_fe_impl_verify(a); +} +#endif /* defined(VERIFY) */ + #endif /* SECP256K1_FIELD_IMPL_H */ From e5cf4bf3ff9aac5b5897a8a9852cfbb84da0bfb1 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Thu, 11 May 2023 10:03:23 +0100 Subject: [PATCH 054/100] build: Rename `arm` to `arm32` --- .cirrus.yml | 2 +- CMakeLists.txt | 10 +++++----- configure.ac | 14 +++++++------- src/CMakeLists.txt | 2 +- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index 592500371b..1560dc7d64 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -176,7 +176,7 @@ task: CTIMETESTS: no matrix: - env: {} - - env: {EXPERIMENTAL: yes, ASM: arm} + - env: {EXPERIMENTAL: yes, ASM: arm32} << : *MERGE_BASE test_script: - ./ci/cirrus.sh diff --git a/CMakeLists.txt b/CMakeLists.txt index cb3b4b510a..a1d9eb36e3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -102,10 +102,10 @@ if(SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY) endif() mark_as_advanced(FORCE SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY) -set(SECP256K1_ASM "AUTO" CACHE STRING "Assembly optimizations to use: \"AUTO\", \"OFF\", \"x86_64\" or \"arm\" (experimental). [default=AUTO]") -set_property(CACHE SECP256K1_ASM PROPERTY STRINGS "AUTO" "OFF" "x86_64" "arm") +set(SECP256K1_ASM "AUTO" CACHE STRING "Assembly optimizations to use: \"AUTO\", \"OFF\", \"x86_64\" or \"arm32\" (experimental). [default=AUTO]") +set_property(CACHE SECP256K1_ASM PROPERTY STRINGS "AUTO" "OFF" "x86_64" "arm32") check_string_option_value(SECP256K1_ASM) -if(SECP256K1_ASM STREQUAL "arm") +if(SECP256K1_ASM STREQUAL "arm32") enable_language(ASM) add_compile_definitions(USE_EXTERNAL_ASM=1) elseif(SECP256K1_ASM) @@ -123,8 +123,8 @@ endif() option(SECP256K1_EXPERIMENTAL "Allow experimental configuration options." OFF) if(NOT SECP256K1_EXPERIMENTAL) - if(SECP256K1_ASM STREQUAL "arm") - message(FATAL_ERROR "ARM assembly optimization is experimental. Use -DSECP256K1_EXPERIMENTAL=ON to allow.") + if(SECP256K1_ASM STREQUAL "arm32") + message(FATAL_ERROR "ARM32 assembly optimization is experimental. Use -DSECP256K1_EXPERIMENTAL=ON to allow.") endif() endif() diff --git a/configure.ac b/configure.ac index 6bf5b573dd..0b99aa3a98 100644 --- a/configure.ac +++ b/configure.ac @@ -197,8 +197,8 @@ AC_ARG_ENABLE(external_default_callbacks, # * and auto (the default). AC_ARG_WITH([test-override-wide-multiply], [] ,[set_widemul=$withval], [set_widemul=auto]) -AC_ARG_WITH([asm], [AS_HELP_STRING([--with-asm=x86_64|arm|no|auto], -[assembly optimizations to use (experimental: arm) [default=auto]])],[req_asm=$withval], [req_asm=auto]) +AC_ARG_WITH([asm], [AS_HELP_STRING([--with-asm=x86_64|arm32|no|auto], +[assembly optimizations to use (experimental: arm32) [default=auto]])],[req_asm=$withval], [req_asm=auto]) AC_ARG_WITH([ecmult-window], [AS_HELP_STRING([--with-ecmult-window=SIZE|auto], [window size for ecmult precomputation for verification, specified as integer in range [2..24].] @@ -279,7 +279,7 @@ else AC_MSG_ERROR([x86_64 assembly optimization requested but not available]) fi ;; - arm) + arm32) ;; no) ;; @@ -296,7 +296,7 @@ case $set_asm in x86_64) SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DUSE_ASM_X86_64=1" ;; -arm) +arm32) enable_external_asm=yes ;; no) @@ -413,8 +413,8 @@ if test x"$enable_experimental" = x"yes"; then AC_MSG_NOTICE([Experimental features do not have stable APIs or properties, and may not be safe for production use.]) AC_MSG_NOTICE([******]) else - if test x"$set_asm" = x"arm"; then - AC_MSG_ERROR([ARM assembly optimization is experimental. Use --enable-experimental to allow.]) + if test x"$set_asm" = x"arm32"; then + AC_MSG_ERROR([ARM32 assembly optimization is experimental. Use --enable-experimental to allow.]) fi fi @@ -436,7 +436,7 @@ AM_CONDITIONAL([ENABLE_MODULE_RECOVERY], [test x"$enable_module_recovery" = x"ye AM_CONDITIONAL([ENABLE_MODULE_EXTRAKEYS], [test x"$enable_module_extrakeys" = x"yes"]) AM_CONDITIONAL([ENABLE_MODULE_SCHNORRSIG], [test x"$enable_module_schnorrsig" = x"yes"]) AM_CONDITIONAL([USE_EXTERNAL_ASM], [test x"$enable_external_asm" = x"yes"]) -AM_CONDITIONAL([USE_ASM_ARM], [test x"$set_asm" = x"arm"]) +AM_CONDITIONAL([USE_ASM_ARM], [test x"$set_asm" = x"arm32"]) AM_CONDITIONAL([BUILD_WINDOWS], [test "$build_windows" = "yes"]) AC_SUBST(LIB_VERSION_CURRENT, _LIB_VERSION_CURRENT) AC_SUBST(LIB_VERSION_REVISION, _LIB_VERSION_REVISION) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ad8c1a93ba..93844caa7f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -11,7 +11,7 @@ add_library(secp256k1_precomputed OBJECT EXCLUDE_FROM_ALL add_library(secp256k1 secp256k1.c $) add_library(secp256k1_asm INTERFACE) -if(SECP256K1_ASM STREQUAL "arm") +if(SECP256K1_ASM STREQUAL "arm32") add_library(secp256k1_asm_arm OBJECT EXCLUDE_FROM_ALL) target_sources(secp256k1_asm_arm PUBLIC asm/field_10x26_arm.s From 7fa51955592ccf4fb424a7a538372ad159e77293 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Tue, 1 Feb 2022 11:15:09 -0500 Subject: [PATCH 055/100] Bugfix: correct SECP256K1_FE_CONST mag/norm fields --- src/field.h | 20 ++++++++++++++++++++ src/field_10x26.h | 6 ------ src/field_5x52.h | 6 ------ 3 files changed, 20 insertions(+), 12 deletions(-) diff --git a/src/field.h b/src/field.h index 28ebe85ac1..3914f6b47a 100644 --- a/src/field.h +++ b/src/field.h @@ -45,6 +45,26 @@ #error "Please select wide multiplication implementation" #endif +#ifdef VERIFY +/* Magnitude and normalized value for constants. */ +#define SECP256K1_FE_VERIFY_CONST(d7, d6, d5, d4, d3, d2, d1, d0) \ + /* Magnitude is 0 for constant 0; 1 otherwise. */ \ + , (((d7) | (d6) | (d5) | (d4) | (d3) | (d2) | (d1) | (d0)) != 0) \ + /* Normalized is 1 unless sum(d_i<<(32*i) for i=0..7) exceeds field modulus. */ \ + , (!(((d7) & (d6) & (d5) & (d4) & (d3) & (d2)) == 0xfffffffful && ((d1) == 0xfffffffful || ((d1) == 0xfffffffe && (d0 >= 0xfffffc2f))))) +#else +#define SECP256K1_FE_VERIFY_CONST(d7, d6, d5, d4, d3, d2, d1, d0) +#endif + +/** This expands to an initializer for a secp256k1_fe valued sum((i*32) * d_i, i=0..7) mod p. + * + * It has magnitude 1, unless d_i are all 0, in which case the magnitude is 0. + * It is normalized, unless sum(2^(i*32) * d_i, i=0..7) >= p. + * + * SECP256K1_FE_CONST_INNER is provided by the implementation. + */ +#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0)) SECP256K1_FE_VERIFY_CONST((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0)) } + static const secp256k1_fe secp256k1_fe_one = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1); static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST( 0x7ae96a2bul, 0x657c0710ul, 0x6e64479eul, 0xac3434e9ul, diff --git a/src/field_10x26.h b/src/field_10x26.h index 4fe36d08e2..203c10167c 100644 --- a/src/field_10x26.h +++ b/src/field_10x26.h @@ -47,12 +47,6 @@ typedef struct { (((uint32_t)d7) >> 10) \ } -#ifdef VERIFY -#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0)), 1, 1} -#else -#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0))} -#endif - typedef struct { uint32_t n[8]; } secp256k1_fe_storage; diff --git a/src/field_5x52.h b/src/field_5x52.h index e4646a56be..f20c246fdd 100644 --- a/src/field_5x52.h +++ b/src/field_5x52.h @@ -42,12 +42,6 @@ typedef struct { ((uint64_t)(d6) >> 16) | (((uint64_t)(d7)) << 16) \ } -#ifdef VERIFY -#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0)), 1, 1} -#else -#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0))} -#endif - typedef struct { uint64_t n[4]; } secp256k1_fe_storage; From b6b6f9cb97f6c9313871c278ec73f209ef537a44 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 28 Jan 2022 17:51:12 -0500 Subject: [PATCH 056/100] Abstract out verify logic for fe_normalize --- src/field.h | 7 +++++-- src/field_10x26_impl.h | 8 +------- src/field_5x52_impl.h | 8 +------- src/field_impl.h | 9 +++++++++ 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/field.h b/src/field.h index 3914f6b47a..161df2b3ed 100644 --- a/src/field.h +++ b/src/field.h @@ -75,10 +75,13 @@ static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST( /* In non-VERIFY mode, we #define the fe operations to be identical to their * internal field implementation, to avoid the potential overhead of a * function call (even though presumably inlinable). */ +# define secp256k1_fe_normalize secp256k1_fe_impl_normalize #endif /* !defined(VERIFY) */ -/** Normalize a field element. This brings the field element to a canonical representation, reduces - * its magnitude to 1, and reduces it modulo field size `p`. +/** Normalize a field element. + * + * On input, r must be a valid field element. + * On output, r represents the same value but has normalized=1 and magnitude=1. */ static void secp256k1_fe_normalize(secp256k1_fe *r); diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h index 8115f534ad..537000a8d1 100644 --- a/src/field_10x26_impl.h +++ b/src/field_10x26_impl.h @@ -58,7 +58,7 @@ static void secp256k1_fe_get_bounds(secp256k1_fe *r, int m) { #endif } -static void secp256k1_fe_normalize(secp256k1_fe *r) { +static void secp256k1_fe_impl_normalize(secp256k1_fe *r) { uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4], t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9]; @@ -105,12 +105,6 @@ static void secp256k1_fe_normalize(secp256k1_fe *r) { r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; r->n[5] = t5; r->n[6] = t6; r->n[7] = t7; r->n[8] = t8; r->n[9] = t9; - -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 1; - secp256k1_fe_verify(r); -#endif } static void secp256k1_fe_normalize_weak(secp256k1_fe *r) { diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h index cd240577f7..820bc3466f 100644 --- a/src/field_5x52_impl.h +++ b/src/field_5x52_impl.h @@ -52,7 +52,7 @@ static void secp256k1_fe_get_bounds(secp256k1_fe *r, int m) { #endif } -static void secp256k1_fe_normalize(secp256k1_fe *r) { +static void secp256k1_fe_impl_normalize(secp256k1_fe *r) { uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4]; /* Reduce t4 at the start so there will be at most a single carry from the first pass */ @@ -87,12 +87,6 @@ static void secp256k1_fe_normalize(secp256k1_fe *r) { t4 &= 0x0FFFFFFFFFFFFULL; r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; - -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 1; - secp256k1_fe_verify(r); -#endif } static void secp256k1_fe_normalize_weak(secp256k1_fe *r) { diff --git a/src/field_impl.h b/src/field_impl.h index 9920dfdb78..f3341db0e4 100644 --- a/src/field_impl.h +++ b/src/field_impl.h @@ -147,6 +147,15 @@ static void secp256k1_fe_verify(const secp256k1_fe *a) { /* Invoke implementation-specific checks. */ secp256k1_fe_impl_verify(a); } + +static void secp256k1_fe_impl_normalize(secp256k1_fe *r); +SECP256K1_INLINE static void secp256k1_fe_normalize(secp256k1_fe *r) { + secp256k1_fe_verify(r); + secp256k1_fe_impl_normalize(r); + r->magnitude = 1; + r->normalized = 1; + secp256k1_fe_verify(r); +} #endif /* defined(VERIFY) */ #endif /* SECP256K1_FIELD_IMPL_H */ From e28b51f52254b93805350354567a944ca4d79ae2 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 28 Jan 2022 17:54:22 -0500 Subject: [PATCH 057/100] Abstract out verify logic for fe_normalize_weak --- src/field.h | 7 ++++++- src/field_10x26_impl.h | 7 +------ src/field_5x52_impl.h | 7 +------ src/field_impl.h | 8 ++++++++ 4 files changed, 16 insertions(+), 13 deletions(-) diff --git a/src/field.h b/src/field.h index 161df2b3ed..ba2d57bba9 100644 --- a/src/field.h +++ b/src/field.h @@ -76,6 +76,7 @@ static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST( * internal field implementation, to avoid the potential overhead of a * function call (even though presumably inlinable). */ # define secp256k1_fe_normalize secp256k1_fe_impl_normalize +# define secp256k1_fe_normalize_weak secp256k1_fe_impl_normalize_weak #endif /* !defined(VERIFY) */ /** Normalize a field element. @@ -85,7 +86,11 @@ static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST( */ static void secp256k1_fe_normalize(secp256k1_fe *r); -/** Weakly normalize a field element: reduce its magnitude to 1, but don't fully normalize. */ +/** Give a field element magnitude 1. + * + * On input, r must be a valid field element. + * On output, r represents the same value but has magnitude=1. Normalized is unchanged. + */ static void secp256k1_fe_normalize_weak(secp256k1_fe *r); /** Normalize a field element, without constant-time guarantee. */ diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h index 537000a8d1..b76111641c 100644 --- a/src/field_10x26_impl.h +++ b/src/field_10x26_impl.h @@ -107,7 +107,7 @@ static void secp256k1_fe_impl_normalize(secp256k1_fe *r) { r->n[5] = t5; r->n[6] = t6; r->n[7] = t7; r->n[8] = t8; r->n[9] = t9; } -static void secp256k1_fe_normalize_weak(secp256k1_fe *r) { +static void secp256k1_fe_impl_normalize_weak(secp256k1_fe *r) { uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4], t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9]; @@ -131,11 +131,6 @@ static void secp256k1_fe_normalize_weak(secp256k1_fe *r) { r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; r->n[5] = t5; r->n[6] = t6; r->n[7] = t7; r->n[8] = t8; r->n[9] = t9; - -#ifdef VERIFY - r->magnitude = 1; - secp256k1_fe_verify(r); -#endif } static void secp256k1_fe_normalize_var(secp256k1_fe *r) { diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h index 820bc3466f..09f3d74900 100644 --- a/src/field_5x52_impl.h +++ b/src/field_5x52_impl.h @@ -89,7 +89,7 @@ static void secp256k1_fe_impl_normalize(secp256k1_fe *r) { r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; } -static void secp256k1_fe_normalize_weak(secp256k1_fe *r) { +static void secp256k1_fe_impl_normalize_weak(secp256k1_fe *r) { uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4]; /* Reduce t4 at the start so there will be at most a single carry from the first pass */ @@ -106,11 +106,6 @@ static void secp256k1_fe_normalize_weak(secp256k1_fe *r) { VERIFY_CHECK(t4 >> 49 == 0); r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; - -#ifdef VERIFY - r->magnitude = 1; - secp256k1_fe_verify(r); -#endif } static void secp256k1_fe_normalize_var(secp256k1_fe *r) { diff --git a/src/field_impl.h b/src/field_impl.h index f3341db0e4..3928e417c6 100644 --- a/src/field_impl.h +++ b/src/field_impl.h @@ -156,6 +156,14 @@ SECP256K1_INLINE static void secp256k1_fe_normalize(secp256k1_fe *r) { r->normalized = 1; secp256k1_fe_verify(r); } + +static void secp256k1_fe_impl_normalize_weak(secp256k1_fe *r); +SECP256K1_INLINE static void secp256k1_fe_normalize_weak(secp256k1_fe *r) { + secp256k1_fe_verify(r); + secp256k1_fe_impl_normalize_weak(r); + r->magnitude = 1; + secp256k1_fe_verify(r); +} #endif /* defined(VERIFY) */ #endif /* SECP256K1_FIELD_IMPL_H */ From 6c31371120bb85a397bf1caa73fd1c9b8405d35e Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 28 Jan 2022 17:59:36 -0500 Subject: [PATCH 058/100] Abstract out verify logic for fe_normalize_var --- src/field.h | 6 +++++- src/field_10x26_impl.h | 8 +------- src/field_5x52_impl.h | 8 +------- src/field_impl.h | 9 +++++++++ 4 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/field.h b/src/field.h index ba2d57bba9..cae92b5866 100644 --- a/src/field.h +++ b/src/field.h @@ -77,6 +77,7 @@ static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST( * function call (even though presumably inlinable). */ # define secp256k1_fe_normalize secp256k1_fe_impl_normalize # define secp256k1_fe_normalize_weak secp256k1_fe_impl_normalize_weak +# define secp256k1_fe_normalize_var secp256k1_fe_impl_normalize_var #endif /* !defined(VERIFY) */ /** Normalize a field element. @@ -93,7 +94,10 @@ static void secp256k1_fe_normalize(secp256k1_fe *r); */ static void secp256k1_fe_normalize_weak(secp256k1_fe *r); -/** Normalize a field element, without constant-time guarantee. */ +/** Normalize a field element, without constant-time guarantee. + * + * Identical in behavior to secp256k1_fe_normalize, but not constant time in r. + */ static void secp256k1_fe_normalize_var(secp256k1_fe *r); /** Verify whether a field element represents zero i.e. would normalize to a zero value. */ diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h index b76111641c..7043da3dea 100644 --- a/src/field_10x26_impl.h +++ b/src/field_10x26_impl.h @@ -133,7 +133,7 @@ static void secp256k1_fe_impl_normalize_weak(secp256k1_fe *r) { r->n[5] = t5; r->n[6] = t6; r->n[7] = t7; r->n[8] = t8; r->n[9] = t9; } -static void secp256k1_fe_normalize_var(secp256k1_fe *r) { +static void secp256k1_fe_impl_normalize_var(secp256k1_fe *r) { uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4], t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9]; @@ -181,12 +181,6 @@ static void secp256k1_fe_normalize_var(secp256k1_fe *r) { r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; r->n[5] = t5; r->n[6] = t6; r->n[7] = t7; r->n[8] = t8; r->n[9] = t9; - -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 1; - secp256k1_fe_verify(r); -#endif } static int secp256k1_fe_normalizes_to_zero(const secp256k1_fe *r) { diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h index 09f3d74900..6594972def 100644 --- a/src/field_5x52_impl.h +++ b/src/field_5x52_impl.h @@ -108,7 +108,7 @@ static void secp256k1_fe_impl_normalize_weak(secp256k1_fe *r) { r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; } -static void secp256k1_fe_normalize_var(secp256k1_fe *r) { +static void secp256k1_fe_impl_normalize_var(secp256k1_fe *r) { uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4]; /* Reduce t4 at the start so there will be at most a single carry from the first pass */ @@ -144,12 +144,6 @@ static void secp256k1_fe_normalize_var(secp256k1_fe *r) { } r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; - -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 1; - secp256k1_fe_verify(r); -#endif } static int secp256k1_fe_normalizes_to_zero(const secp256k1_fe *r) { diff --git a/src/field_impl.h b/src/field_impl.h index 3928e417c6..414e3e188c 100644 --- a/src/field_impl.h +++ b/src/field_impl.h @@ -164,6 +164,15 @@ SECP256K1_INLINE static void secp256k1_fe_normalize_weak(secp256k1_fe *r) { r->magnitude = 1; secp256k1_fe_verify(r); } + +static void secp256k1_fe_impl_normalize_var(secp256k1_fe *r); +SECP256K1_INLINE static void secp256k1_fe_normalize_var(secp256k1_fe *r) { + secp256k1_fe_verify(r); + secp256k1_fe_impl_normalize_var(r); + r->magnitude = 1; + r->normalized = 1; + secp256k1_fe_verify(r); +} #endif /* defined(VERIFY) */ #endif /* SECP256K1_FIELD_IMPL_H */ From 864f9db491b4e1204fda5168174b235f9eefb56e Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Mon, 31 Jan 2022 16:51:10 -0500 Subject: [PATCH 059/100] Abstract out verify logic for fe_normalizes_to_zero{,_var} --- src/field.h | 14 +++++++++++--- src/field_10x26_impl.h | 4 ++-- src/field_5x52_impl.h | 4 ++-- src/field_impl.h | 12 ++++++++++++ 4 files changed, 27 insertions(+), 7 deletions(-) diff --git a/src/field.h b/src/field.h index cae92b5866..8db62a92eb 100644 --- a/src/field.h +++ b/src/field.h @@ -78,6 +78,8 @@ static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST( # define secp256k1_fe_normalize secp256k1_fe_impl_normalize # define secp256k1_fe_normalize_weak secp256k1_fe_impl_normalize_weak # define secp256k1_fe_normalize_var secp256k1_fe_impl_normalize_var +# define secp256k1_fe_normalizes_to_zero secp256k1_fe_impl_normalizes_to_zero +# define secp256k1_fe_normalizes_to_zero_var secp256k1_fe_impl_normalizes_to_zero_var #endif /* !defined(VERIFY) */ /** Normalize a field element. @@ -100,11 +102,17 @@ static void secp256k1_fe_normalize_weak(secp256k1_fe *r); */ static void secp256k1_fe_normalize_var(secp256k1_fe *r); -/** Verify whether a field element represents zero i.e. would normalize to a zero value. */ +/** Determine whether r represents field element 0. + * + * On input, r must be a valid field element. + * Returns whether r = 0 (mod p). + */ static int secp256k1_fe_normalizes_to_zero(const secp256k1_fe *r); -/** Verify whether a field element represents zero i.e. would normalize to a zero value, - * without constant-time guarantee. */ +/** Determine whether r represents field element 0, without constant-time guarantee. + * + * Identical in behavior to secp256k1_normalizes_to_zero, but not constant time in r. + */ static int secp256k1_fe_normalizes_to_zero_var(const secp256k1_fe *r); /** Set a field element equal to a small (not greater than 0x7FFF), non-negative integer. diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h index 7043da3dea..e107bee8a8 100644 --- a/src/field_10x26_impl.h +++ b/src/field_10x26_impl.h @@ -183,7 +183,7 @@ static void secp256k1_fe_impl_normalize_var(secp256k1_fe *r) { r->n[5] = t5; r->n[6] = t6; r->n[7] = t7; r->n[8] = t8; r->n[9] = t9; } -static int secp256k1_fe_normalizes_to_zero(const secp256k1_fe *r) { +static int secp256k1_fe_impl_normalizes_to_zero(const secp256k1_fe *r) { uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4], t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9]; @@ -212,7 +212,7 @@ static int secp256k1_fe_normalizes_to_zero(const secp256k1_fe *r) { return (z0 == 0) | (z1 == 0x3FFFFFFUL); } -static int secp256k1_fe_normalizes_to_zero_var(const secp256k1_fe *r) { +static int secp256k1_fe_impl_normalizes_to_zero_var(const secp256k1_fe *r) { uint32_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9; uint32_t z0, z1; uint32_t x; diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h index 6594972def..1a8960ff1e 100644 --- a/src/field_5x52_impl.h +++ b/src/field_5x52_impl.h @@ -146,7 +146,7 @@ static void secp256k1_fe_impl_normalize_var(secp256k1_fe *r) { r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; } -static int secp256k1_fe_normalizes_to_zero(const secp256k1_fe *r) { +static int secp256k1_fe_impl_normalizes_to_zero(const secp256k1_fe *r) { uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4]; /* z0 tracks a possible raw value of 0, z1 tracks a possible raw value of P */ @@ -169,7 +169,7 @@ static int secp256k1_fe_normalizes_to_zero(const secp256k1_fe *r) { return (z0 == 0) | (z1 == 0xFFFFFFFFFFFFFULL); } -static int secp256k1_fe_normalizes_to_zero_var(const secp256k1_fe *r) { +static int secp256k1_fe_impl_normalizes_to_zero_var(const secp256k1_fe *r) { uint64_t t0, t1, t2, t3, t4; uint64_t z0, z1; uint64_t x; diff --git a/src/field_impl.h b/src/field_impl.h index 414e3e188c..ae54693859 100644 --- a/src/field_impl.h +++ b/src/field_impl.h @@ -173,6 +173,18 @@ SECP256K1_INLINE static void secp256k1_fe_normalize_var(secp256k1_fe *r) { r->normalized = 1; secp256k1_fe_verify(r); } + +static int secp256k1_fe_impl_normalizes_to_zero(const secp256k1_fe *r); +SECP256K1_INLINE static int secp256k1_fe_normalizes_to_zero(const secp256k1_fe *r) { + secp256k1_fe_verify(r); + return secp256k1_fe_impl_normalizes_to_zero(r); +} + +static int secp256k1_fe_impl_normalizes_to_zero_var(const secp256k1_fe *r); +SECP256K1_INLINE static int secp256k1_fe_normalizes_to_zero_var(const secp256k1_fe *r) { + secp256k1_fe_verify(r); + return secp256k1_fe_impl_normalizes_to_zero_var(r); +} #endif /* defined(VERIFY) */ #endif /* SECP256K1_FIELD_IMPL_H */ From 19a2bfeeeac4274bbeca7f8757a2ee73bdf03895 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 28 Jan 2022 18:04:15 -0500 Subject: [PATCH 060/100] Abstract out verify logic for fe_set_int --- src/field.h | 7 +++++-- src/field_10x26_impl.h | 8 +------- src/field_5x52_impl.h | 8 +------- src/field_impl.h | 9 +++++++++ 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/field.h b/src/field.h index 8db62a92eb..e841f14ee0 100644 --- a/src/field.h +++ b/src/field.h @@ -80,6 +80,7 @@ static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST( # define secp256k1_fe_normalize_var secp256k1_fe_impl_normalize_var # define secp256k1_fe_normalizes_to_zero secp256k1_fe_impl_normalizes_to_zero # define secp256k1_fe_normalizes_to_zero_var secp256k1_fe_impl_normalizes_to_zero_var +# define secp256k1_fe_set_int secp256k1_fe_impl_set_int #endif /* !defined(VERIFY) */ /** Normalize a field element. @@ -115,8 +116,10 @@ static int secp256k1_fe_normalizes_to_zero(const secp256k1_fe *r); */ static int secp256k1_fe_normalizes_to_zero_var(const secp256k1_fe *r); -/** Set a field element equal to a small (not greater than 0x7FFF), non-negative integer. - * Resulting field element is normalized; it has magnitude 0 if a == 0, and magnitude 1 otherwise. +/** Set a field element to an integer in range [0,0x7FFF]. + * + * On input, r does not need to be initialized, a must be in [0,0x7FFF]. + * On output, r represents value a, is normalized and has magnitude (a!=0). */ static void secp256k1_fe_set_int(secp256k1_fe *r, int a); diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h index e107bee8a8..70be960f8a 100644 --- a/src/field_10x26_impl.h +++ b/src/field_10x26_impl.h @@ -264,15 +264,9 @@ static int secp256k1_fe_impl_normalizes_to_zero_var(const secp256k1_fe *r) { return (z0 == 0) | (z1 == 0x3FFFFFFUL); } -SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe *r, int a) { - VERIFY_CHECK(0 <= a && a <= 0x7FFF); +SECP256K1_INLINE static void secp256k1_fe_impl_set_int(secp256k1_fe *r, int a) { r->n[0] = a; r->n[1] = r->n[2] = r->n[3] = r->n[4] = r->n[5] = r->n[6] = r->n[7] = r->n[8] = r->n[9] = 0; -#ifdef VERIFY - r->magnitude = (a != 0); - r->normalized = 1; - secp256k1_fe_verify(r); -#endif } SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe *a) { diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h index 1a8960ff1e..c735257f53 100644 --- a/src/field_5x52_impl.h +++ b/src/field_5x52_impl.h @@ -210,15 +210,9 @@ static int secp256k1_fe_impl_normalizes_to_zero_var(const secp256k1_fe *r) { return (z0 == 0) | (z1 == 0xFFFFFFFFFFFFFULL); } -SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe *r, int a) { - VERIFY_CHECK(0 <= a && a <= 0x7FFF); +SECP256K1_INLINE static void secp256k1_fe_impl_set_int(secp256k1_fe *r, int a) { r->n[0] = a; r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0; -#ifdef VERIFY - r->magnitude = (a != 0); - r->normalized = 1; - secp256k1_fe_verify(r); -#endif } SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe *a) { diff --git a/src/field_impl.h b/src/field_impl.h index ae54693859..0083aabc8d 100644 --- a/src/field_impl.h +++ b/src/field_impl.h @@ -185,6 +185,15 @@ SECP256K1_INLINE static int secp256k1_fe_normalizes_to_zero_var(const secp256k1_ secp256k1_fe_verify(r); return secp256k1_fe_impl_normalizes_to_zero_var(r); } + +static void secp256k1_fe_impl_set_int(secp256k1_fe *r, int a); +SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe *r, int a) { + VERIFY_CHECK(0 <= a && a <= 0x7FFF); + secp256k1_fe_impl_set_int(r, a); + r->magnitude = (a != 0); + r->normalized = 1; + secp256k1_fe_verify(r); +} #endif /* defined(VERIFY) */ #endif /* SECP256K1_FIELD_IMPL_H */ From c701d9a4719adff20fa83511f946e4abbd4d8cda Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Mon, 31 Jan 2022 17:15:41 -0500 Subject: [PATCH 061/100] Abstract out verify logic for fe_clear --- src/field.h | 7 ++++++- src/field_10x26_impl.h | 6 +----- src/field_5x52_impl.h | 6 +----- src/field_impl.h | 8 ++++++++ 4 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/field.h b/src/field.h index e841f14ee0..f6f3fa9f17 100644 --- a/src/field.h +++ b/src/field.h @@ -81,6 +81,7 @@ static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST( # define secp256k1_fe_normalizes_to_zero secp256k1_fe_impl_normalizes_to_zero # define secp256k1_fe_normalizes_to_zero_var secp256k1_fe_impl_normalizes_to_zero_var # define secp256k1_fe_set_int secp256k1_fe_impl_set_int +# define secp256k1_fe_clear secp256k1_fe_impl_clear #endif /* !defined(VERIFY) */ /** Normalize a field element. @@ -123,7 +124,11 @@ static int secp256k1_fe_normalizes_to_zero_var(const secp256k1_fe *r); */ static void secp256k1_fe_set_int(secp256k1_fe *r, int a); -/** Sets a field element equal to zero, initializing all fields. */ +/** Set a field element to 0. + * + * On input, a does not need to be initialized. + * On output, a represents 0, is normalized and has magnitude 0. + */ static void secp256k1_fe_clear(secp256k1_fe *a); /** Verify whether a field element is zero. Requires the input to be normalized. */ diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h index 70be960f8a..7fc9993e00 100644 --- a/src/field_10x26_impl.h +++ b/src/field_10x26_impl.h @@ -286,12 +286,8 @@ SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe *a) { return a->n[0] & 1; } -SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe *a) { +SECP256K1_INLINE static void secp256k1_fe_impl_clear(secp256k1_fe *a) { int i; -#ifdef VERIFY - a->magnitude = 0; - a->normalized = 1; -#endif for (i=0; i<10; i++) { a->n[i] = 0; } diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h index c735257f53..d2c4a6ba25 100644 --- a/src/field_5x52_impl.h +++ b/src/field_5x52_impl.h @@ -232,12 +232,8 @@ SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe *a) { return a->n[0] & 1; } -SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe *a) { +SECP256K1_INLINE static void secp256k1_fe_impl_clear(secp256k1_fe *a) { int i; -#ifdef VERIFY - a->magnitude = 0; - a->normalized = 1; -#endif for (i=0; i<5; i++) { a->n[i] = 0; } diff --git a/src/field_impl.h b/src/field_impl.h index 0083aabc8d..0eccf75023 100644 --- a/src/field_impl.h +++ b/src/field_impl.h @@ -194,6 +194,14 @@ SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe *r, int a) { r->normalized = 1; secp256k1_fe_verify(r); } + +static void secp256k1_fe_impl_clear(secp256k1_fe *a); +SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe *a) { + a->magnitude = 0; + a->normalized = 1; + secp256k1_fe_impl_clear(a); + secp256k1_fe_verify(a); +} #endif /* defined(VERIFY) */ #endif /* SECP256K1_FIELD_IMPL_H */ From d3f3fe8616d02bd1c62376c1318be69c64eea982 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 28 Jan 2022 18:07:55 -0500 Subject: [PATCH 062/100] Abstract out verify logic for fe_is_zero --- src/field.h | 10 +++++++++- src/field_10x26_impl.h | 6 +----- src/field_5x52_impl.h | 6 +----- src/field_impl.h | 7 +++++++ 4 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/field.h b/src/field.h index f6f3fa9f17..c057472c28 100644 --- a/src/field.h +++ b/src/field.h @@ -82,6 +82,7 @@ static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST( # define secp256k1_fe_normalizes_to_zero_var secp256k1_fe_impl_normalizes_to_zero_var # define secp256k1_fe_set_int secp256k1_fe_impl_set_int # define secp256k1_fe_clear secp256k1_fe_impl_clear +# define secp256k1_fe_is_zero secp256k1_fe_impl_is_zero #endif /* !defined(VERIFY) */ /** Normalize a field element. @@ -131,7 +132,14 @@ static void secp256k1_fe_set_int(secp256k1_fe *r, int a); */ static void secp256k1_fe_clear(secp256k1_fe *a); -/** Verify whether a field element is zero. Requires the input to be normalized. */ +/** Determine whether a represents field element 0. + * + * On input, a must be a valid normalized field element. + * Returns whether a = 0 (mod p). + * + * This behaves identical to secp256k1_normalizes_to_zero{,_var}, but requires + * normalized input (and is much faster). + */ static int secp256k1_fe_is_zero(const secp256k1_fe *a); /** Check the "oddness" of a field element. Requires the input to be normalized. */ diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h index 7fc9993e00..5e934c438c 100644 --- a/src/field_10x26_impl.h +++ b/src/field_10x26_impl.h @@ -269,12 +269,8 @@ SECP256K1_INLINE static void secp256k1_fe_impl_set_int(secp256k1_fe *r, int a) { r->n[1] = r->n[2] = r->n[3] = r->n[4] = r->n[5] = r->n[6] = r->n[7] = r->n[8] = r->n[9] = 0; } -SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe *a) { +SECP256K1_INLINE static int secp256k1_fe_impl_is_zero(const secp256k1_fe *a) { const uint32_t *t = a->n; -#ifdef VERIFY - VERIFY_CHECK(a->normalized); - secp256k1_fe_verify(a); -#endif return (t[0] | t[1] | t[2] | t[3] | t[4] | t[5] | t[6] | t[7] | t[8] | t[9]) == 0; } diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h index d2c4a6ba25..0572d77bec 100644 --- a/src/field_5x52_impl.h +++ b/src/field_5x52_impl.h @@ -215,12 +215,8 @@ SECP256K1_INLINE static void secp256k1_fe_impl_set_int(secp256k1_fe *r, int a) { r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0; } -SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe *a) { +SECP256K1_INLINE static int secp256k1_fe_impl_is_zero(const secp256k1_fe *a) { const uint64_t *t = a->n; -#ifdef VERIFY - VERIFY_CHECK(a->normalized); - secp256k1_fe_verify(a); -#endif return (t[0] | t[1] | t[2] | t[3] | t[4]) == 0; } diff --git a/src/field_impl.h b/src/field_impl.h index 0eccf75023..8c85134057 100644 --- a/src/field_impl.h +++ b/src/field_impl.h @@ -202,6 +202,13 @@ SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe *a) { secp256k1_fe_impl_clear(a); secp256k1_fe_verify(a); } + +static int secp256k1_fe_impl_is_zero(const secp256k1_fe *a); +SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe *a) { + secp256k1_fe_verify(a); + VERIFY_CHECK(a->normalized); + return secp256k1_fe_impl_is_zero(a); +} #endif /* defined(VERIFY) */ #endif /* SECP256K1_FIELD_IMPL_H */ From c5e788d672d78315e7269fd3743eadae6428468e Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 28 Jan 2022 18:11:21 -0500 Subject: [PATCH 063/100] Abstract out verify logic for fe_is_odd --- src/field.h | 7 ++++++- src/field_10x26_impl.h | 6 +----- src/field_5x52_impl.h | 6 +----- src/field_impl.h | 7 +++++++ 4 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/field.h b/src/field.h index c057472c28..9e517dca80 100644 --- a/src/field.h +++ b/src/field.h @@ -83,6 +83,7 @@ static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST( # define secp256k1_fe_set_int secp256k1_fe_impl_set_int # define secp256k1_fe_clear secp256k1_fe_impl_clear # define secp256k1_fe_is_zero secp256k1_fe_impl_is_zero +# define secp256k1_fe_is_odd secp256k1_fe_impl_is_odd #endif /* !defined(VERIFY) */ /** Normalize a field element. @@ -142,7 +143,11 @@ static void secp256k1_fe_clear(secp256k1_fe *a); */ static int secp256k1_fe_is_zero(const secp256k1_fe *a); -/** Check the "oddness" of a field element. Requires the input to be normalized. */ +/** Determine whether a (mod p) is odd. + * + * On input, a must be a valid normalized field element. + * Returns (int(a) mod p) & 1. + */ static int secp256k1_fe_is_odd(const secp256k1_fe *a); /** Compare two field elements. Requires magnitude-1 inputs. */ diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h index 5e934c438c..e7305abb3e 100644 --- a/src/field_10x26_impl.h +++ b/src/field_10x26_impl.h @@ -274,11 +274,7 @@ SECP256K1_INLINE static int secp256k1_fe_impl_is_zero(const secp256k1_fe *a) { return (t[0] | t[1] | t[2] | t[3] | t[4] | t[5] | t[6] | t[7] | t[8] | t[9]) == 0; } -SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe *a) { -#ifdef VERIFY - VERIFY_CHECK(a->normalized); - secp256k1_fe_verify(a); -#endif +SECP256K1_INLINE static int secp256k1_fe_impl_is_odd(const secp256k1_fe *a) { return a->n[0] & 1; } diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h index 0572d77bec..31c3bcb7a6 100644 --- a/src/field_5x52_impl.h +++ b/src/field_5x52_impl.h @@ -220,11 +220,7 @@ SECP256K1_INLINE static int secp256k1_fe_impl_is_zero(const secp256k1_fe *a) { return (t[0] | t[1] | t[2] | t[3] | t[4]) == 0; } -SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe *a) { -#ifdef VERIFY - VERIFY_CHECK(a->normalized); - secp256k1_fe_verify(a); -#endif +SECP256K1_INLINE static int secp256k1_fe_impl_is_odd(const secp256k1_fe *a) { return a->n[0] & 1; } diff --git a/src/field_impl.h b/src/field_impl.h index 8c85134057..bd6982033c 100644 --- a/src/field_impl.h +++ b/src/field_impl.h @@ -209,6 +209,13 @@ SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe *a) { VERIFY_CHECK(a->normalized); return secp256k1_fe_impl_is_zero(a); } + +static int secp256k1_fe_impl_is_odd(const secp256k1_fe *a); +SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe *a) { + secp256k1_fe_verify(a); + VERIFY_CHECK(a->normalized); + return secp256k1_fe_impl_is_odd(a); +} #endif /* defined(VERIFY) */ #endif /* SECP256K1_FIELD_IMPL_H */ From 7d7d43c6dd2741853de4631881d77ae38a14cd23 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Mon, 31 Jan 2022 17:34:36 -0500 Subject: [PATCH 064/100] Improve comments/check for fe_equal{,_var} --- src/field.h | 12 ++++++++++-- src/field_impl.h | 12 ++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/field.h b/src/field.h index 9e517dca80..e7b64e78eb 100644 --- a/src/field.h +++ b/src/field.h @@ -150,10 +150,18 @@ static int secp256k1_fe_is_zero(const secp256k1_fe *a); */ static int secp256k1_fe_is_odd(const secp256k1_fe *a); -/** Compare two field elements. Requires magnitude-1 inputs. */ +/** Determine whether two field elements are equal. + * + * On input, a and b must be valid field elements with magnitudes not exceeding + * 1 and 31, respectively. + * Returns a = b (mod p). + */ static int secp256k1_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b); -/** Same as secp256k1_fe_equal, but may be variable time. */ +/** Determine whether two field elements are equal, without constant-time guarantee. + * + * Identical in behavior to secp256k1_fe_equal, but not constant time in either a or b. + */ static int secp256k1_fe_equal_var(const secp256k1_fe *a, const secp256k1_fe *b); /** Compare two field elements. Requires both inputs to be normalized */ diff --git a/src/field_impl.h b/src/field_impl.h index bd6982033c..dae82aa67e 100644 --- a/src/field_impl.h +++ b/src/field_impl.h @@ -20,6 +20,12 @@ SECP256K1_INLINE static int secp256k1_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b) { secp256k1_fe na; +#ifdef VERIFY + secp256k1_fe_verify(a); + secp256k1_fe_verify(b); + VERIFY_CHECK(a->magnitude <= 1); + VERIFY_CHECK(b->magnitude <= 31); +#endif secp256k1_fe_negate(&na, a, 1); secp256k1_fe_add(&na, b); return secp256k1_fe_normalizes_to_zero(&na); @@ -27,6 +33,12 @@ SECP256K1_INLINE static int secp256k1_fe_equal(const secp256k1_fe *a, const secp SECP256K1_INLINE static int secp256k1_fe_equal_var(const secp256k1_fe *a, const secp256k1_fe *b) { secp256k1_fe na; +#ifdef VERIFY + secp256k1_fe_verify(a); + secp256k1_fe_verify(b); + VERIFY_CHECK(a->magnitude <= 1); + VERIFY_CHECK(b->magnitude <= 31); +#endif secp256k1_fe_negate(&na, a, 1); secp256k1_fe_add(&na, b); return secp256k1_fe_normalizes_to_zero_var(&na); From ce4d2093e86fedca676dbbe59b50bdcf8c599704 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 28 Jan 2022 18:16:16 -0500 Subject: [PATCH 065/100] Abstract out verify logic for fe_cmp_var --- src/field.h | 8 +++++++- src/field_10x26_impl.h | 8 +------- src/field_5x52_impl.h | 8 +------- src/field_impl.h | 9 +++++++++ 4 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/field.h b/src/field.h index e7b64e78eb..4145d89c80 100644 --- a/src/field.h +++ b/src/field.h @@ -84,6 +84,7 @@ static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST( # define secp256k1_fe_clear secp256k1_fe_impl_clear # define secp256k1_fe_is_zero secp256k1_fe_impl_is_zero # define secp256k1_fe_is_odd secp256k1_fe_impl_is_odd +# define secp256k1_fe_cmp_var secp256k1_fe_impl_cmp_var #endif /* !defined(VERIFY) */ /** Normalize a field element. @@ -164,7 +165,12 @@ static int secp256k1_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b); */ static int secp256k1_fe_equal_var(const secp256k1_fe *a, const secp256k1_fe *b); -/** Compare two field elements. Requires both inputs to be normalized */ +/** Compare the values represented by 2 field elements, without constant-time guarantee. + * + * On input, a and b must be valid normalized field elements. + * Returns 1 if a > b, -1 if a < b, and 0 if a = b (comparisons are done as integers + * in range 0..p-1). + */ static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b); /** Set a field element equal to 32-byte big endian value. diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h index e7305abb3e..a7a0186b71 100644 --- a/src/field_10x26_impl.h +++ b/src/field_10x26_impl.h @@ -285,14 +285,8 @@ SECP256K1_INLINE static void secp256k1_fe_impl_clear(secp256k1_fe *a) { } } -static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) { +static int secp256k1_fe_impl_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) { int i; -#ifdef VERIFY - VERIFY_CHECK(a->normalized); - VERIFY_CHECK(b->normalized); - secp256k1_fe_verify(a); - secp256k1_fe_verify(b); -#endif for (i = 9; i >= 0; i--) { if (a->n[i] > b->n[i]) { return 1; diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h index 31c3bcb7a6..b4af5d69a0 100644 --- a/src/field_5x52_impl.h +++ b/src/field_5x52_impl.h @@ -231,14 +231,8 @@ SECP256K1_INLINE static void secp256k1_fe_impl_clear(secp256k1_fe *a) { } } -static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) { +static int secp256k1_fe_impl_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) { int i; -#ifdef VERIFY - VERIFY_CHECK(a->normalized); - VERIFY_CHECK(b->normalized); - secp256k1_fe_verify(a); - secp256k1_fe_verify(b); -#endif for (i = 4; i >= 0; i--) { if (a->n[i] > b->n[i]) { return 1; diff --git a/src/field_impl.h b/src/field_impl.h index dae82aa67e..4424ddb173 100644 --- a/src/field_impl.h +++ b/src/field_impl.h @@ -228,6 +228,15 @@ SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe *a) { VERIFY_CHECK(a->normalized); return secp256k1_fe_impl_is_odd(a); } + +static int secp256k1_fe_impl_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b); +SECP256K1_INLINE static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) { + secp256k1_fe_verify(a); + secp256k1_fe_verify(b); + VERIFY_CHECK(a->normalized); + VERIFY_CHECK(b->normalized); + return secp256k1_fe_impl_cmp_var(a, b); +} #endif /* defined(VERIFY) */ #endif /* SECP256K1_FIELD_IMPL_H */ From f7a7666aeb8db92b9171f4765f7d405b7b73d946 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 28 Jan 2022 18:19:00 -0500 Subject: [PATCH 066/100] Abstract out verify logic for fe_set_b32 --- src/field.h | 13 ++++++++++--- src/field_10x26_impl.h | 11 ++--------- src/field_5x52_impl.h | 11 ++--------- src/field_impl.h | 9 +++++++++ 4 files changed, 23 insertions(+), 21 deletions(-) diff --git a/src/field.h b/src/field.h index 4145d89c80..b1c434eaf6 100644 --- a/src/field.h +++ b/src/field.h @@ -85,6 +85,7 @@ static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST( # define secp256k1_fe_is_zero secp256k1_fe_impl_is_zero # define secp256k1_fe_is_odd secp256k1_fe_impl_is_odd # define secp256k1_fe_cmp_var secp256k1_fe_impl_cmp_var +# define secp256k1_fe_set_b32 secp256k1_fe_impl_set_b32 #endif /* !defined(VERIFY) */ /** Normalize a field element. @@ -173,9 +174,15 @@ static int secp256k1_fe_equal_var(const secp256k1_fe *a, const secp256k1_fe *b); */ static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b); -/** Set a field element equal to 32-byte big endian value. - * Returns 1 if no overflow occurred, and then the output is normalized. - * Returns 0 if overflow occurred, and then the output is only weakly normalized. */ +/** Set a field element equal to a provided 32-byte big endian value. + * + * On input, r does not need to be initalized. a must be a pointer to an initialized 32-byte array. + * On output, r = a (mod p). It will have magnitude 1, and if (a < p), it will be normalized. + * If not, it will only be weakly normalized. Returns whether (a < p). + * + * Note that this function is unusual in that the normalization of the output depends on the + * run-time value of a. + */ static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a); /** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */ diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h index a7a0186b71..5e0b65d652 100644 --- a/src/field_10x26_impl.h +++ b/src/field_10x26_impl.h @@ -298,8 +298,7 @@ static int secp256k1_fe_impl_cmp_var(const secp256k1_fe *a, const secp256k1_fe * return 0; } -static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a) { - int ret; +static int secp256k1_fe_impl_set_b32(secp256k1_fe *r, const unsigned char *a) { r->n[0] = (uint32_t)a[31] | ((uint32_t)a[30] << 8) | ((uint32_t)a[29] << 16) | ((uint32_t)(a[28] & 0x3) << 24); r->n[1] = (uint32_t)((a[28] >> 2) & 0x3f) | ((uint32_t)a[27] << 6) | ((uint32_t)a[26] << 14) | ((uint32_t)(a[25] & 0xf) << 22); r->n[2] = (uint32_t)((a[25] >> 4) & 0xf) | ((uint32_t)a[24] << 4) | ((uint32_t)a[23] << 12) | ((uint32_t)(a[22] & 0x3f) << 20); @@ -311,13 +310,7 @@ static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a) { r->n[8] = (uint32_t)a[5] | ((uint32_t)a[4] << 8) | ((uint32_t)a[3] << 16) | ((uint32_t)(a[2] & 0x3) << 24); r->n[9] = (uint32_t)((a[2] >> 2) & 0x3f) | ((uint32_t)a[1] << 6) | ((uint32_t)a[0] << 14); - ret = !((r->n[9] == 0x3FFFFFUL) & ((r->n[8] & r->n[7] & r->n[6] & r->n[5] & r->n[4] & r->n[3] & r->n[2]) == 0x3FFFFFFUL) & ((r->n[1] + 0x40UL + ((r->n[0] + 0x3D1UL) >> 26)) > 0x3FFFFFFUL)); -#ifdef VERIFY - r->magnitude = 1; - r->normalized = ret; - secp256k1_fe_verify(r); -#endif - return ret; + return !((r->n[9] == 0x3FFFFFUL) & ((r->n[8] & r->n[7] & r->n[6] & r->n[5] & r->n[4] & r->n[3] & r->n[2]) == 0x3FFFFFFUL) & ((r->n[1] + 0x40UL + ((r->n[0] + 0x3D1UL) >> 26)) > 0x3FFFFFFUL)); } /** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */ diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h index b4af5d69a0..b06b485b7f 100644 --- a/src/field_5x52_impl.h +++ b/src/field_5x52_impl.h @@ -244,8 +244,7 @@ static int secp256k1_fe_impl_cmp_var(const secp256k1_fe *a, const secp256k1_fe * return 0; } -static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a) { - int ret; +static int secp256k1_fe_impl_set_b32(secp256k1_fe *r, const unsigned char *a) { r->n[0] = (uint64_t)a[31] | ((uint64_t)a[30] << 8) | ((uint64_t)a[29] << 16) @@ -280,13 +279,7 @@ static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a) { | ((uint64_t)a[2] << 24) | ((uint64_t)a[1] << 32) | ((uint64_t)a[0] << 40); - ret = !((r->n[4] == 0x0FFFFFFFFFFFFULL) & ((r->n[3] & r->n[2] & r->n[1]) == 0xFFFFFFFFFFFFFULL) & (r->n[0] >= 0xFFFFEFFFFFC2FULL)); -#ifdef VERIFY - r->magnitude = 1; - r->normalized = ret; - secp256k1_fe_verify(r); -#endif - return ret; + return !((r->n[4] == 0x0FFFFFFFFFFFFULL) & ((r->n[3] & r->n[2] & r->n[1]) == 0xFFFFFFFFFFFFFULL) & (r->n[0] >= 0xFFFFEFFFFFC2FULL)); } /** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */ diff --git a/src/field_impl.h b/src/field_impl.h index 4424ddb173..304c428cb7 100644 --- a/src/field_impl.h +++ b/src/field_impl.h @@ -237,6 +237,15 @@ SECP256K1_INLINE static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const se VERIFY_CHECK(b->normalized); return secp256k1_fe_impl_cmp_var(a, b); } + +static int secp256k1_fe_impl_set_b32(secp256k1_fe *r, const unsigned char *a); +SECP256K1_INLINE static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a) { + int ret = secp256k1_fe_impl_set_b32(r, a); + r->magnitude = 1; + r->normalized = ret; + secp256k1_fe_verify(r); + return ret; +} #endif /* defined(VERIFY) */ #endif /* SECP256K1_FIELD_IMPL_H */ From 144670893eccd84d638951f6c5bae43fc97e3c7b Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 28 Jan 2022 18:23:54 -0500 Subject: [PATCH 067/100] Abstract out verify logic for fe_get_b32 --- src/field.h | 6 +++++- src/field_10x26_impl.h | 6 +----- src/field_5x52_impl.h | 6 +----- src/field_impl.h | 7 +++++++ 4 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/field.h b/src/field.h index b1c434eaf6..327e63fc96 100644 --- a/src/field.h +++ b/src/field.h @@ -86,6 +86,7 @@ static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST( # define secp256k1_fe_is_odd secp256k1_fe_impl_is_odd # define secp256k1_fe_cmp_var secp256k1_fe_impl_cmp_var # define secp256k1_fe_set_b32 secp256k1_fe_impl_set_b32 +# define secp256k1_fe_get_b32 secp256k1_fe_impl_get_b32 #endif /* !defined(VERIFY) */ /** Normalize a field element. @@ -185,7 +186,10 @@ static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b); */ static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a); -/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */ +/** Convert a field element to 32-byte big endian byte array. + * On input, a must be a valid normalized field element, and r a pointer to a 32-byte array. + * On output, r = a (mod p). + */ static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a); /** Set a field element equal to the additive inverse of another. Takes a maximum magnitude of the input diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h index 5e0b65d652..c3f49c86eb 100644 --- a/src/field_10x26_impl.h +++ b/src/field_10x26_impl.h @@ -314,11 +314,7 @@ static int secp256k1_fe_impl_set_b32(secp256k1_fe *r, const unsigned char *a) { } /** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */ -static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a) { -#ifdef VERIFY - VERIFY_CHECK(a->normalized); - secp256k1_fe_verify(a); -#endif +static void secp256k1_fe_impl_get_b32(unsigned char *r, const secp256k1_fe *a) { r[0] = (a->n[9] >> 14) & 0xff; r[1] = (a->n[9] >> 6) & 0xff; r[2] = ((a->n[9] & 0x3F) << 2) | ((a->n[8] >> 24) & 0x3); diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h index b06b485b7f..0994087c56 100644 --- a/src/field_5x52_impl.h +++ b/src/field_5x52_impl.h @@ -283,11 +283,7 @@ static int secp256k1_fe_impl_set_b32(secp256k1_fe *r, const unsigned char *a) { } /** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */ -static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a) { -#ifdef VERIFY - VERIFY_CHECK(a->normalized); - secp256k1_fe_verify(a); -#endif +static void secp256k1_fe_impl_get_b32(unsigned char *r, const secp256k1_fe *a) { r[0] = (a->n[4] >> 40) & 0xFF; r[1] = (a->n[4] >> 32) & 0xFF; r[2] = (a->n[4] >> 24) & 0xFF; diff --git a/src/field_impl.h b/src/field_impl.h index 304c428cb7..a09c7a6be1 100644 --- a/src/field_impl.h +++ b/src/field_impl.h @@ -246,6 +246,13 @@ SECP256K1_INLINE static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned secp256k1_fe_verify(r); return ret; } + +static void secp256k1_fe_impl_get_b32(unsigned char *r, const secp256k1_fe *a); +SECP256K1_INLINE static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a) { + secp256k1_fe_verify(a); + VERIFY_CHECK(a->normalized); + secp256k1_fe_impl_get_b32(r, a); +} #endif /* defined(VERIFY) */ #endif /* SECP256K1_FIELD_IMPL_H */ From 65d82a3445265767375383a5b68b5f61aeadefca Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 28 Jan 2022 18:27:38 -0500 Subject: [PATCH 068/100] Abstract out verify logic for fe_negate --- src/field.h | 10 ++++++++-- src/field_10x26_impl.h | 15 +++++---------- src/field_5x52_impl.h | 15 +++++---------- src/field_impl.h | 11 +++++++++++ 4 files changed, 29 insertions(+), 22 deletions(-) diff --git a/src/field.h b/src/field.h index 327e63fc96..b1bc4b979e 100644 --- a/src/field.h +++ b/src/field.h @@ -87,6 +87,7 @@ static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST( # define secp256k1_fe_cmp_var secp256k1_fe_impl_cmp_var # define secp256k1_fe_set_b32 secp256k1_fe_impl_set_b32 # define secp256k1_fe_get_b32 secp256k1_fe_impl_get_b32 +# define secp256k1_fe_negate secp256k1_fe_impl_negate #endif /* !defined(VERIFY) */ /** Normalize a field element. @@ -192,8 +193,13 @@ static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a); */ static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a); -/** Set a field element equal to the additive inverse of another. Takes a maximum magnitude of the input - * as an argument. The magnitude of the output is one higher. */ +/** Negate a field element. + * + * On input, r does not need to be initialized. a must be a valid field element with + * magnitude not exceeding m. m must be an integer in [0,31]. + * Performs {r = -a}. + * On output, r will not be normalized, and will have magnitude m+1. + */ static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m); /** Adds a small integer (up to 0x7FFF) to r. The resulting magnitude increases by one. */ diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h index c3f49c86eb..9e29f6adf9 100644 --- a/src/field_10x26_impl.h +++ b/src/field_10x26_impl.h @@ -349,15 +349,15 @@ static void secp256k1_fe_impl_get_b32(unsigned char *r, const secp256k1_fe *a) { r[31] = a->n[0] & 0xff; } -SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m) { -#ifdef VERIFY - VERIFY_CHECK(a->magnitude <= m); - secp256k1_fe_verify(a); +SECP256K1_INLINE static void secp256k1_fe_impl_negate(secp256k1_fe *r, const secp256k1_fe *a, int m) { + /* For all legal values of m (0..31), the following properties hold: */ VERIFY_CHECK(0x3FFFC2FUL * 2 * (m + 1) >= 0x3FFFFFFUL * 2 * m); VERIFY_CHECK(0x3FFFFBFUL * 2 * (m + 1) >= 0x3FFFFFFUL * 2 * m); VERIFY_CHECK(0x3FFFFFFUL * 2 * (m + 1) >= 0x3FFFFFFUL * 2 * m); VERIFY_CHECK(0x03FFFFFUL * 2 * (m + 1) >= 0x03FFFFFUL * 2 * m); -#endif + + /* Due to the properties above, the left hand in the subtractions below is never less than + * the right hand. */ r->n[0] = 0x3FFFC2FUL * 2 * (m + 1) - a->n[0]; r->n[1] = 0x3FFFFBFUL * 2 * (m + 1) - a->n[1]; r->n[2] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[2]; @@ -368,11 +368,6 @@ SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k r->n[7] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[7]; r->n[8] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[8]; r->n[9] = 0x03FFFFFUL * 2 * (m + 1) - a->n[9]; -#ifdef VERIFY - r->magnitude = m + 1; - r->normalized = 0; - secp256k1_fe_verify(r); -#endif } SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe *r, int a) { diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h index 0994087c56..4775ee0cee 100644 --- a/src/field_5x52_impl.h +++ b/src/field_5x52_impl.h @@ -318,24 +318,19 @@ static void secp256k1_fe_impl_get_b32(unsigned char *r, const secp256k1_fe *a) { r[31] = a->n[0] & 0xFF; } -SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m) { -#ifdef VERIFY - VERIFY_CHECK(a->magnitude <= m); - secp256k1_fe_verify(a); +SECP256K1_INLINE static void secp256k1_fe_impl_negate(secp256k1_fe *r, const secp256k1_fe *a, int m) { + /* For all legal values of m (0..31), the following properties hold: */ VERIFY_CHECK(0xFFFFEFFFFFC2FULL * 2 * (m + 1) >= 0xFFFFFFFFFFFFFULL * 2 * m); VERIFY_CHECK(0xFFFFFFFFFFFFFULL * 2 * (m + 1) >= 0xFFFFFFFFFFFFFULL * 2 * m); VERIFY_CHECK(0x0FFFFFFFFFFFFULL * 2 * (m + 1) >= 0x0FFFFFFFFFFFFULL * 2 * m); -#endif + + /* Due to the properties above, the left hand in the subtractions below is never less than + * the right hand. */ r->n[0] = 0xFFFFEFFFFFC2FULL * 2 * (m + 1) - a->n[0]; r->n[1] = 0xFFFFFFFFFFFFFULL * 2 * (m + 1) - a->n[1]; r->n[2] = 0xFFFFFFFFFFFFFULL * 2 * (m + 1) - a->n[2]; r->n[3] = 0xFFFFFFFFFFFFFULL * 2 * (m + 1) - a->n[3]; r->n[4] = 0x0FFFFFFFFFFFFULL * 2 * (m + 1) - a->n[4]; -#ifdef VERIFY - r->magnitude = m + 1; - r->normalized = 0; - secp256k1_fe_verify(r); -#endif } SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe *r, int a) { diff --git a/src/field_impl.h b/src/field_impl.h index a09c7a6be1..1c70795169 100644 --- a/src/field_impl.h +++ b/src/field_impl.h @@ -253,6 +253,17 @@ SECP256K1_INLINE static void secp256k1_fe_get_b32(unsigned char *r, const secp25 VERIFY_CHECK(a->normalized); secp256k1_fe_impl_get_b32(r, a); } + +static void secp256k1_fe_impl_negate(secp256k1_fe *r, const secp256k1_fe *a, int m); +SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m) { + secp256k1_fe_verify(a); + VERIFY_CHECK(m >= 0 && m <= 31); + VERIFY_CHECK(a->magnitude <= m); + secp256k1_fe_impl_negate(r, a, m); + r->magnitude = m + 1; + r->normalized = 0; + secp256k1_fe_verify(r); +} #endif /* defined(VERIFY) */ #endif /* SECP256K1_FIELD_IMPL_H */ From 7e7ad7ff570645304459242104406d6e1f79857c Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 28 Jan 2022 18:33:45 -0500 Subject: [PATCH 069/100] Abstract out verify logic for fe_mul_int --- src/field.h | 10 ++++++++-- src/field_10x26_impl.h | 7 +------ src/field_5x52_impl.h | 7 +------ src/field_impl.h | 11 +++++++++++ 4 files changed, 21 insertions(+), 14 deletions(-) diff --git a/src/field.h b/src/field.h index b1bc4b979e..2c1e9d2e1a 100644 --- a/src/field.h +++ b/src/field.h @@ -88,6 +88,7 @@ static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST( # define secp256k1_fe_set_b32 secp256k1_fe_impl_set_b32 # define secp256k1_fe_get_b32 secp256k1_fe_impl_get_b32 # define secp256k1_fe_negate secp256k1_fe_impl_negate +# define secp256k1_fe_mul_int secp256k1_fe_impl_mul_int #endif /* !defined(VERIFY) */ /** Normalize a field element. @@ -205,8 +206,13 @@ static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m); /** Adds a small integer (up to 0x7FFF) to r. The resulting magnitude increases by one. */ static void secp256k1_fe_add_int(secp256k1_fe *r, int a); -/** Multiplies the passed field element with a small integer constant. Multiplies the magnitude by that - * small integer. */ +/** Multiply a field element with a small integer. + * + * On input, r must be a valid field element. a must be an integer in [0,32]. + * The magnitude of r times a must not exceed 32. + * Performs {r *= a}. + * On output, r's magnitude is multiplied by a, and r will not be normalized. + */ static void secp256k1_fe_mul_int(secp256k1_fe *r, int a); /** Adds a field element to another. The result has the sum of the inputs' magnitudes as magnitude. */ diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h index 9e29f6adf9..f8c8ddb5b4 100644 --- a/src/field_10x26_impl.h +++ b/src/field_10x26_impl.h @@ -370,7 +370,7 @@ SECP256K1_INLINE static void secp256k1_fe_impl_negate(secp256k1_fe *r, const sec r->n[9] = 0x03FFFFFUL * 2 * (m + 1) - a->n[9]; } -SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe *r, int a) { +SECP256K1_INLINE static void secp256k1_fe_impl_mul_int(secp256k1_fe *r, int a) { r->n[0] *= a; r->n[1] *= a; r->n[2] *= a; @@ -381,11 +381,6 @@ SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe *r, int a) { r->n[7] *= a; r->n[8] *= a; r->n[9] *= a; -#ifdef VERIFY - r->magnitude *= a; - r->normalized = 0; - secp256k1_fe_verify(r); -#endif } SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a) { diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h index 4775ee0cee..f509137340 100644 --- a/src/field_5x52_impl.h +++ b/src/field_5x52_impl.h @@ -333,17 +333,12 @@ SECP256K1_INLINE static void secp256k1_fe_impl_negate(secp256k1_fe *r, const sec r->n[4] = 0x0FFFFFFFFFFFFULL * 2 * (m + 1) - a->n[4]; } -SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe *r, int a) { +SECP256K1_INLINE static void secp256k1_fe_impl_mul_int(secp256k1_fe *r, int a) { r->n[0] *= a; r->n[1] *= a; r->n[2] *= a; r->n[3] *= a; r->n[4] *= a; -#ifdef VERIFY - r->magnitude *= a; - r->normalized = 0; - secp256k1_fe_verify(r); -#endif } SECP256K1_INLINE static void secp256k1_fe_add_int(secp256k1_fe *r, int a) { diff --git a/src/field_impl.h b/src/field_impl.h index 1c70795169..8bd18c61ab 100644 --- a/src/field_impl.h +++ b/src/field_impl.h @@ -264,6 +264,17 @@ SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k r->normalized = 0; secp256k1_fe_verify(r); } + +static void secp256k1_fe_impl_mul_int(secp256k1_fe *r, int a); +SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe *r, int a) { + secp256k1_fe_verify(r); + VERIFY_CHECK(a >= 0 && a <= 32); + VERIFY_CHECK(a*r->magnitude <= 32); + secp256k1_fe_impl_mul_int(r, a); + r->magnitude *= a; + r->normalized = 0; + secp256k1_fe_verify(r); +} #endif /* defined(VERIFY) */ #endif /* SECP256K1_FIELD_IMPL_H */ From e179e651cbb20031905e01f37596e20ec2cb788a Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 28 Jan 2022 18:36:13 -0500 Subject: [PATCH 070/100] Abstract out verify logic for fe_add --- src/field.h | 9 ++++++++- src/field_10x26_impl.h | 8 +------- src/field_5x52_impl.h | 8 +------- src/field_impl.h | 11 +++++++++++ 4 files changed, 21 insertions(+), 15 deletions(-) diff --git a/src/field.h b/src/field.h index 2c1e9d2e1a..988bc6f390 100644 --- a/src/field.h +++ b/src/field.h @@ -89,6 +89,7 @@ static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST( # define secp256k1_fe_get_b32 secp256k1_fe_impl_get_b32 # define secp256k1_fe_negate secp256k1_fe_impl_negate # define secp256k1_fe_mul_int secp256k1_fe_impl_mul_int +# define secp256k1_fe_add secp256k1_fe_impl_add #endif /* !defined(VERIFY) */ /** Normalize a field element. @@ -215,7 +216,13 @@ static void secp256k1_fe_add_int(secp256k1_fe *r, int a); */ static void secp256k1_fe_mul_int(secp256k1_fe *r, int a); -/** Adds a field element to another. The result has the sum of the inputs' magnitudes as magnitude. */ +/** Increment a field element by another. + * + * On input, r and a must be valid field elements, not necessarily normalized. + * The sum of their magnitudes must not exceed 32. + * Performs {r += a}. + * On output, r will not be normalized, and will have magnitude incremented by a's. + */ static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a); /** Sets a field element to be the product of two others. Requires the inputs' magnitudes to be at most 8. diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h index f8c8ddb5b4..eefd4da697 100644 --- a/src/field_10x26_impl.h +++ b/src/field_10x26_impl.h @@ -383,8 +383,7 @@ SECP256K1_INLINE static void secp256k1_fe_impl_mul_int(secp256k1_fe *r, int a) { r->n[9] *= a; } -SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a) { - secp256k1_fe_verify(a); +SECP256K1_INLINE static void secp256k1_fe_impl_add(secp256k1_fe *r, const secp256k1_fe *a) { r->n[0] += a->n[0]; r->n[1] += a->n[1]; r->n[2] += a->n[2]; @@ -395,11 +394,6 @@ SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_f r->n[7] += a->n[7]; r->n[8] += a->n[8]; r->n[9] += a->n[9]; -#ifdef VERIFY - r->magnitude += a->magnitude; - r->normalized = 0; - secp256k1_fe_verify(r); -#endif } SECP256K1_INLINE static void secp256k1_fe_add_int(secp256k1_fe *r, int a) { diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h index f509137340..8bd084ff27 100644 --- a/src/field_5x52_impl.h +++ b/src/field_5x52_impl.h @@ -353,18 +353,12 @@ SECP256K1_INLINE static void secp256k1_fe_add_int(secp256k1_fe *r, int a) { #endif } -SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a) { - secp256k1_fe_verify(a); +SECP256K1_INLINE static void secp256k1_fe_impl_add(secp256k1_fe *r, const secp256k1_fe *a) { r->n[0] += a->n[0]; r->n[1] += a->n[1]; r->n[2] += a->n[2]; r->n[3] += a->n[3]; r->n[4] += a->n[4]; -#ifdef VERIFY - r->magnitude += a->magnitude; - r->normalized = 0; - secp256k1_fe_verify(r); -#endif } static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) { diff --git a/src/field_impl.h b/src/field_impl.h index 8bd18c61ab..172b846d89 100644 --- a/src/field_impl.h +++ b/src/field_impl.h @@ -275,6 +275,17 @@ SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe *r, int a) { r->normalized = 0; secp256k1_fe_verify(r); } + +static void secp256k1_fe_impl_add(secp256k1_fe *r, const secp256k1_fe *a); +SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a) { + secp256k1_fe_verify(r); + secp256k1_fe_verify(a); + VERIFY_CHECK(r->magnitude + a->magnitude <= 32); + secp256k1_fe_impl_add(r, a); + r->magnitude += a->magnitude; + r->normalized = 0; + secp256k1_fe_verify(r); +} #endif /* defined(VERIFY) */ #endif /* SECP256K1_FIELD_IMPL_H */ From 4c25f6efbd5f8b4738c1c16daf73906d45c5f579 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 28 Jan 2022 18:40:33 -0500 Subject: [PATCH 071/100] Abstract out verify logic for fe_mul --- src/field.h | 11 +++++++++-- src/field_10x26_impl.h | 15 +-------------- src/field_5x52_impl.h | 15 +-------------- src/field_impl.h | 14 ++++++++++++++ 4 files changed, 25 insertions(+), 30 deletions(-) diff --git a/src/field.h b/src/field.h index 988bc6f390..c301841b29 100644 --- a/src/field.h +++ b/src/field.h @@ -90,6 +90,7 @@ static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST( # define secp256k1_fe_negate secp256k1_fe_impl_negate # define secp256k1_fe_mul_int secp256k1_fe_impl_mul_int # define secp256k1_fe_add secp256k1_fe_impl_add +# define secp256k1_fe_mul secp256k1_fe_impl_mul #endif /* !defined(VERIFY) */ /** Normalize a field element. @@ -225,8 +226,14 @@ static void secp256k1_fe_mul_int(secp256k1_fe *r, int a); */ static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a); -/** Sets a field element to be the product of two others. Requires the inputs' magnitudes to be at most 8. - * The output magnitude is 1 (but not guaranteed to be normalized). */ +/** Multiply two field elements. + * + * On input, a and b must be valid field elements; r does not need to be initialized. + * r and a may point to the same object, but neither can be equal to b. The magnitudes + * of a and b must not exceed 8. + * Performs {r = a * b} + * On output, r will have magnitude 1, but won't be normalized. + */ static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b); /** Sets a field element to be the square of another. Requires the input's magnitude to be at most 8. diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h index eefd4da697..f2cc4ad1e3 100644 --- a/src/field_10x26_impl.h +++ b/src/field_10x26_impl.h @@ -1027,21 +1027,8 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint32_t *r, const uint32_t } #endif -static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) { -#ifdef VERIFY - VERIFY_CHECK(a->magnitude <= 8); - VERIFY_CHECK(b->magnitude <= 8); - secp256k1_fe_verify(a); - secp256k1_fe_verify(b); - VERIFY_CHECK(r != b); - VERIFY_CHECK(a != b); -#endif +SECP256K1_INLINE static void secp256k1_fe_impl_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) { secp256k1_fe_mul_inner(r->n, a->n, b->n); -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 0; - secp256k1_fe_verify(r); -#endif } static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a) { diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h index 8bd084ff27..adfac57778 100644 --- a/src/field_5x52_impl.h +++ b/src/field_5x52_impl.h @@ -361,21 +361,8 @@ SECP256K1_INLINE static void secp256k1_fe_impl_add(secp256k1_fe *r, const secp25 r->n[4] += a->n[4]; } -static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) { -#ifdef VERIFY - VERIFY_CHECK(a->magnitude <= 8); - VERIFY_CHECK(b->magnitude <= 8); - secp256k1_fe_verify(a); - secp256k1_fe_verify(b); - VERIFY_CHECK(r != b); - VERIFY_CHECK(a != b); -#endif +SECP256K1_INLINE static void secp256k1_fe_impl_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) { secp256k1_fe_mul_inner(r->n, a->n, b->n); -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 0; - secp256k1_fe_verify(r); -#endif } static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a) { diff --git a/src/field_impl.h b/src/field_impl.h index 172b846d89..0def1e57d5 100644 --- a/src/field_impl.h +++ b/src/field_impl.h @@ -286,6 +286,20 @@ SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_f r->normalized = 0; secp256k1_fe_verify(r); } + +static void secp256k1_fe_impl_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b); +SECP256K1_INLINE static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) { + secp256k1_fe_verify(a); + secp256k1_fe_verify(b); + VERIFY_CHECK(a->magnitude <= 8); + VERIFY_CHECK(b->magnitude <= 8); + VERIFY_CHECK(r != b); + VERIFY_CHECK(a != b); + secp256k1_fe_impl_mul(r, a, b); + r->magnitude = 1; + r->normalized = 0; + secp256k1_fe_verify(r); +} #endif /* defined(VERIFY) */ #endif /* SECP256K1_FIELD_IMPL_H */ From 6ab35082efe904cbb7ca5225134a1d3647e35388 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 28 Jan 2022 18:42:47 -0500 Subject: [PATCH 072/100] Abstract out verify logic for fe_sqr --- src/field.h | 10 ++++++++-- src/field_10x26_impl.h | 11 +---------- src/field_5x52_impl.h | 11 +---------- src/field_impl.h | 10 ++++++++++ 4 files changed, 20 insertions(+), 22 deletions(-) diff --git a/src/field.h b/src/field.h index c301841b29..597c9fe338 100644 --- a/src/field.h +++ b/src/field.h @@ -91,6 +91,7 @@ static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST( # define secp256k1_fe_mul_int secp256k1_fe_impl_mul_int # define secp256k1_fe_add secp256k1_fe_impl_add # define secp256k1_fe_mul secp256k1_fe_impl_mul +# define secp256k1_fe_sqr secp256k1_fe_impl_sqr #endif /* !defined(VERIFY) */ /** Normalize a field element. @@ -236,8 +237,13 @@ static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a); */ static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b); -/** Sets a field element to be the square of another. Requires the input's magnitude to be at most 8. - * The output magnitude is 1 (but not guaranteed to be normalized). */ +/** Square a field element. + * + * On input, a must be a valid field element; r does not need to be initialized. The magnitude + * of a must not exceed 8. + * Performs {r = a**2} + * On output, r will have magnitude 1, but won't be normalized. + */ static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a); /** If a has a square root, it is computed in r and 1 is returned. If a does not diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h index f2cc4ad1e3..f34f27bb3d 100644 --- a/src/field_10x26_impl.h +++ b/src/field_10x26_impl.h @@ -1031,17 +1031,8 @@ SECP256K1_INLINE static void secp256k1_fe_impl_mul(secp256k1_fe *r, const secp25 secp256k1_fe_mul_inner(r->n, a->n, b->n); } -static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a) { -#ifdef VERIFY - VERIFY_CHECK(a->magnitude <= 8); - secp256k1_fe_verify(a); -#endif +SECP256K1_INLINE static void secp256k1_fe_impl_sqr(secp256k1_fe *r, const secp256k1_fe *a) { secp256k1_fe_sqr_inner(r->n, a->n); -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 0; - secp256k1_fe_verify(r); -#endif } static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) { diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h index adfac57778..5e90218c94 100644 --- a/src/field_5x52_impl.h +++ b/src/field_5x52_impl.h @@ -365,17 +365,8 @@ SECP256K1_INLINE static void secp256k1_fe_impl_mul(secp256k1_fe *r, const secp25 secp256k1_fe_mul_inner(r->n, a->n, b->n); } -static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a) { -#ifdef VERIFY - VERIFY_CHECK(a->magnitude <= 8); - secp256k1_fe_verify(a); -#endif +SECP256K1_INLINE static void secp256k1_fe_impl_sqr(secp256k1_fe *r, const secp256k1_fe *a) { secp256k1_fe_sqr_inner(r->n, a->n); -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 0; - secp256k1_fe_verify(r); -#endif } static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) { diff --git a/src/field_impl.h b/src/field_impl.h index 0def1e57d5..ff4c8eca18 100644 --- a/src/field_impl.h +++ b/src/field_impl.h @@ -300,6 +300,16 @@ SECP256K1_INLINE static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_f r->normalized = 0; secp256k1_fe_verify(r); } + +static void secp256k1_fe_impl_sqr(secp256k1_fe *r, const secp256k1_fe *a); +SECP256K1_INLINE static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a) { + secp256k1_fe_verify(a); + VERIFY_CHECK(a->magnitude <= 8); + secp256k1_fe_impl_sqr(r, a); + r->magnitude = 1; + r->normalized = 0; + secp256k1_fe_verify(r); +} #endif /* defined(VERIFY) */ #endif /* SECP256K1_FIELD_IMPL_H */ From be82bd8e0347e090037ff1d30a22a9d614db8c9f Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Mon, 31 Jan 2022 18:19:45 -0500 Subject: [PATCH 073/100] Improve comments/checks for fe_sqrt --- src/field.h | 14 ++++++++------ src/field_impl.h | 17 +++++++++++++++-- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/field.h b/src/field.h index 597c9fe338..eb6c586b48 100644 --- a/src/field.h +++ b/src/field.h @@ -246,12 +246,14 @@ static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp2 */ static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a); -/** If a has a square root, it is computed in r and 1 is returned. If a does not - * have a square root, the root of its negation is computed and 0 is returned. - * The input's magnitude can be at most 8. The output magnitude is 1 (but not - * guaranteed to be normalized). The result in r will always be a square - * itself. */ -static int secp256k1_fe_sqrt(secp256k1_fe *r, const secp256k1_fe *a); +/** Compute a square root of a field element. + * + * On input, a must be a valid field element with magnitude<=8; r need not be initialized. + * Performs {r = sqrt(a)} or {r = sqrt(-a)}, whichever exists. The resulting value + * represented by r will be a square itself. Variables r and a must not point to the same object. + * On output, r will have magnitude 1 but will not be normalized. + */ +static int secp256k1_fe_sqrt(secp256k1_fe * SECP256K1_RESTRICT r, const secp256k1_fe * SECP256K1_RESTRICT a); /** Sets a field element to be the (modular) inverse of another. Requires the input's magnitude to be * at most 8. The output magnitude is 1 (but not guaranteed to be normalized). */ diff --git a/src/field_impl.h b/src/field_impl.h index ff4c8eca18..89ffc76cc5 100644 --- a/src/field_impl.h +++ b/src/field_impl.h @@ -55,9 +55,13 @@ static int secp256k1_fe_sqrt(secp256k1_fe *r, const secp256k1_fe *a) { * itself always a square (a ** ((p+1)/4) is the square of a ** ((p+1)/8)). */ secp256k1_fe x2, x3, x6, x9, x11, x22, x44, x88, x176, x220, x223, t1; - int j; + int j, ret; +#ifdef VERIFY VERIFY_CHECK(r != a); + secp256k1_fe_verify(a); + VERIFY_CHECK(a->magnitude <= 8); +#endif /** The binary representation of (p + 1)/4 has 3 blocks of 1s, with lengths in * { 2, 22, 223 }. Use an addition chain to calculate 2^n - 1 for each block: @@ -141,7 +145,16 @@ static int secp256k1_fe_sqrt(secp256k1_fe *r, const secp256k1_fe *a) { /* Check that a square root was actually calculated */ secp256k1_fe_sqr(&t1, r); - return secp256k1_fe_equal(&t1, a); + ret = secp256k1_fe_equal(&t1, a); + +#ifdef VERIFY + if (!ret) { + secp256k1_fe_negate(&t1, &t1, 1); + secp256k1_fe_normalize_var(&t1); + VERIFY_CHECK(secp256k1_fe_equal_var(&t1, a)); + } +#endif + return ret; } #ifndef VERIFY From 1e6894bdd74c0b94224f2891c9f5501ac7a3b87a Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 28 Jan 2022 18:45:42 -0500 Subject: [PATCH 074/100] Abstract out verify logic for fe_cmov --- src/field.h | 8 +++++++- src/field_10x26_impl.h | 8 +------- src/field_5x52_impl.h | 8 +------- src/field_impl.h | 13 +++++++++++++ 4 files changed, 22 insertions(+), 15 deletions(-) diff --git a/src/field.h b/src/field.h index eb6c586b48..daa2c54066 100644 --- a/src/field.h +++ b/src/field.h @@ -92,6 +92,7 @@ static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST( # define secp256k1_fe_add secp256k1_fe_impl_add # define secp256k1_fe_mul secp256k1_fe_impl_mul # define secp256k1_fe_sqr secp256k1_fe_impl_sqr +# define secp256k1_fe_cmov secp256k1_fe_impl_cmov #endif /* !defined(VERIFY) */ /** Normalize a field element. @@ -271,7 +272,12 @@ static void secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_fe_storag /** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized.*/ static void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag); -/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized.*/ +/** Conditionally move a field element in constant time. + * + * On input, both r and a must be valid field elements. Flag must be 0 or 1. + * Performs {r = flag ? a : r}. + * On output, r's magnitude and normalized will equal a's in case of flag=1, unchanged otherwise. + */ static void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag); /** Halves the value of a field element modulo the field prime. Constant-time. diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h index f34f27bb3d..6219150170 100644 --- a/src/field_10x26_impl.h +++ b/src/field_10x26_impl.h @@ -1035,7 +1035,7 @@ SECP256K1_INLINE static void secp256k1_fe_impl_sqr(secp256k1_fe *r, const secp25 secp256k1_fe_sqr_inner(r->n, a->n); } -static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) { +SECP256K1_INLINE static void secp256k1_fe_impl_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) { uint32_t mask0, mask1; volatile int vflag = flag; SECP256K1_CHECKMEM_CHECK_VERIFY(r->n, sizeof(r->n)); @@ -1051,12 +1051,6 @@ static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_ r->n[7] = (r->n[7] & mask0) | (a->n[7] & mask1); r->n[8] = (r->n[8] & mask0) | (a->n[8] & mask1); r->n[9] = (r->n[9] & mask0) | (a->n[9] & mask1); -#ifdef VERIFY - if (flag) { - r->magnitude = a->magnitude; - r->normalized = a->normalized; - } -#endif } static SECP256K1_INLINE void secp256k1_fe_half(secp256k1_fe *r) { diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h index 5e90218c94..6a90ef4c4d 100644 --- a/src/field_5x52_impl.h +++ b/src/field_5x52_impl.h @@ -369,7 +369,7 @@ SECP256K1_INLINE static void secp256k1_fe_impl_sqr(secp256k1_fe *r, const secp25 secp256k1_fe_sqr_inner(r->n, a->n); } -static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) { +SECP256K1_INLINE static void secp256k1_fe_impl_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) { uint64_t mask0, mask1; volatile int vflag = flag; SECP256K1_CHECKMEM_CHECK_VERIFY(r->n, sizeof(r->n)); @@ -380,12 +380,6 @@ static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_ r->n[2] = (r->n[2] & mask0) | (a->n[2] & mask1); r->n[3] = (r->n[3] & mask0) | (a->n[3] & mask1); r->n[4] = (r->n[4] & mask0) | (a->n[4] & mask1); -#ifdef VERIFY - if (flag) { - r->magnitude = a->magnitude; - r->normalized = a->normalized; - } -#endif } static SECP256K1_INLINE void secp256k1_fe_half(secp256k1_fe *r) { diff --git a/src/field_impl.h b/src/field_impl.h index 89ffc76cc5..bb1608d25c 100644 --- a/src/field_impl.h +++ b/src/field_impl.h @@ -323,6 +323,19 @@ SECP256K1_INLINE static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_f r->normalized = 0; secp256k1_fe_verify(r); } + +static void secp256k1_fe_impl_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag); +SECP256K1_INLINE static void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) { + VERIFY_CHECK(flag == 0 || flag == 1); + secp256k1_fe_verify(a); + secp256k1_fe_verify(r); + secp256k1_fe_impl_cmov(r, a, flag); + if (flag) { + r->magnitude = a->magnitude; + r->normalized = a->normalized; + } + secp256k1_fe_verify(r); +} #endif /* defined(VERIFY) */ #endif /* SECP256K1_FIELD_IMPL_H */ From 76d31e5047c1d8dfb83b277421f11460f5126a03 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 28 Jan 2022 18:56:54 -0500 Subject: [PATCH 075/100] Abstract out verify logic for fe_to_storage --- src/field.h | 7 ++++++- src/field_10x26_impl.h | 5 +---- src/field_5x52_impl.h | 5 +---- src/field_impl.h | 7 +++++++ 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/field.h b/src/field.h index daa2c54066..4928e256af 100644 --- a/src/field.h +++ b/src/field.h @@ -93,6 +93,7 @@ static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST( # define secp256k1_fe_mul secp256k1_fe_impl_mul # define secp256k1_fe_sqr secp256k1_fe_impl_sqr # define secp256k1_fe_cmov secp256k1_fe_impl_cmov +# define secp256k1_fe_to_storage secp256k1_fe_impl_to_storage #endif /* !defined(VERIFY) */ /** Normalize a field element. @@ -263,7 +264,11 @@ static void secp256k1_fe_inv(secp256k1_fe *r, const secp256k1_fe *a); /** Potentially faster version of secp256k1_fe_inv, without constant-time guarantee. */ static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *a); -/** Convert a field element to the storage type. */ +/** Convert a field element to secp256k1_fe_storage. + * + * On input, a must be a valid normalized field element. + * Performs {r = a}. + */ static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a); /** Convert a field element back from the storage type. */ diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h index 6219150170..b0676eb937 100644 --- a/src/field_10x26_impl.h +++ b/src/field_10x26_impl.h @@ -1145,10 +1145,7 @@ static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, r->n[7] = (r->n[7] & mask0) | (a->n[7] & mask1); } -static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a) { -#ifdef VERIFY - VERIFY_CHECK(a->normalized); -#endif +static void secp256k1_fe_impl_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a) { r->n[0] = a->n[0] | a->n[1] << 26; r->n[1] = a->n[1] >> 6 | a->n[2] << 20; r->n[2] = a->n[2] >> 12 | a->n[3] << 14; diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h index 6a90ef4c4d..d183b0bf7f 100644 --- a/src/field_5x52_impl.h +++ b/src/field_5x52_impl.h @@ -459,10 +459,7 @@ static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, r->n[3] = (r->n[3] & mask0) | (a->n[3] & mask1); } -static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a) { -#ifdef VERIFY - VERIFY_CHECK(a->normalized); -#endif +static void secp256k1_fe_impl_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a) { r->n[0] = a->n[0] | a->n[1] << 52; r->n[1] = a->n[1] >> 12 | a->n[2] << 40; r->n[2] = a->n[2] >> 24 | a->n[3] << 28; diff --git a/src/field_impl.h b/src/field_impl.h index bb1608d25c..fd0d56da25 100644 --- a/src/field_impl.h +++ b/src/field_impl.h @@ -336,6 +336,13 @@ SECP256K1_INLINE static void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_ } secp256k1_fe_verify(r); } + +static void secp256k1_fe_impl_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a); +SECP256K1_INLINE static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a) { + secp256k1_fe_verify(a); + VERIFY_CHECK(a->normalized); + secp256k1_fe_impl_to_storage(r, a); +} #endif /* defined(VERIFY) */ #endif /* SECP256K1_FIELD_IMPL_H */ From 316764607257084e714898e07234fdc53150b57a Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 28 Jan 2022 19:02:03 -0500 Subject: [PATCH 076/100] Abstract out verify logic for fe_from_storage --- src/field.h | 8 +++++++- src/field_10x26_impl.h | 7 +------ src/field_5x52_impl.h | 7 +------ src/field_impl.h | 8 ++++++++ 4 files changed, 17 insertions(+), 13 deletions(-) diff --git a/src/field.h b/src/field.h index 4928e256af..cb330635dc 100644 --- a/src/field.h +++ b/src/field.h @@ -94,6 +94,7 @@ static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST( # define secp256k1_fe_sqr secp256k1_fe_impl_sqr # define secp256k1_fe_cmov secp256k1_fe_impl_cmov # define secp256k1_fe_to_storage secp256k1_fe_impl_to_storage +# define secp256k1_fe_from_storage secp256k1_fe_impl_from_storage #endif /* !defined(VERIFY) */ /** Normalize a field element. @@ -271,7 +272,12 @@ static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *a); */ static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a); -/** Convert a field element back from the storage type. */ +/** Convert a field element back from secp256k1_fe_storage. + * + * On input, r need not be initialized. + * Performs {r = a}. + * On output, r will be normalized and will have magnitude 1. + */ static void secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a); /** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized.*/ diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h index b0676eb937..55d152ec26 100644 --- a/src/field_10x26_impl.h +++ b/src/field_10x26_impl.h @@ -1156,7 +1156,7 @@ static void secp256k1_fe_impl_to_storage(secp256k1_fe_storage *r, const secp256k r->n[7] = a->n[8] >> 16 | a->n[9] << 10; } -static SECP256K1_INLINE void secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a) { +static SECP256K1_INLINE void secp256k1_fe_impl_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a) { r->n[0] = a->n[0] & 0x3FFFFFFUL; r->n[1] = a->n[0] >> 26 | ((a->n[1] << 6) & 0x3FFFFFFUL); r->n[2] = a->n[1] >> 20 | ((a->n[2] << 12) & 0x3FFFFFFUL); @@ -1167,11 +1167,6 @@ static SECP256K1_INLINE void secp256k1_fe_from_storage(secp256k1_fe *r, const se r->n[7] = a->n[5] >> 22 | ((a->n[6] << 10) & 0x3FFFFFFUL); r->n[8] = a->n[6] >> 16 | ((a->n[7] << 16) & 0x3FFFFFFUL); r->n[9] = a->n[7] >> 10; -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 1; - secp256k1_fe_verify(r); -#endif } static void secp256k1_fe_from_signed30(secp256k1_fe *r, const secp256k1_modinv32_signed30 *a) { diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h index d183b0bf7f..1946fbb88b 100644 --- a/src/field_5x52_impl.h +++ b/src/field_5x52_impl.h @@ -466,17 +466,12 @@ static void secp256k1_fe_impl_to_storage(secp256k1_fe_storage *r, const secp256k r->n[3] = a->n[3] >> 36 | a->n[4] << 16; } -static SECP256K1_INLINE void secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a) { +static SECP256K1_INLINE void secp256k1_fe_impl_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a) { r->n[0] = a->n[0] & 0xFFFFFFFFFFFFFULL; r->n[1] = a->n[0] >> 52 | ((a->n[1] << 12) & 0xFFFFFFFFFFFFFULL); r->n[2] = a->n[1] >> 40 | ((a->n[2] << 24) & 0xFFFFFFFFFFFFFULL); r->n[3] = a->n[2] >> 28 | ((a->n[3] << 36) & 0xFFFFFFFFFFFFFULL); r->n[4] = a->n[3] >> 16; -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 1; - secp256k1_fe_verify(r); -#endif } static void secp256k1_fe_from_signed62(secp256k1_fe *r, const secp256k1_modinv64_signed62 *a) { diff --git a/src/field_impl.h b/src/field_impl.h index fd0d56da25..0e1c7630be 100644 --- a/src/field_impl.h +++ b/src/field_impl.h @@ -343,6 +343,14 @@ SECP256K1_INLINE static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, co VERIFY_CHECK(a->normalized); secp256k1_fe_impl_to_storage(r, a); } + +static void secp256k1_fe_impl_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a); +SECP256K1_INLINE static void secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a) { + secp256k1_fe_impl_from_storage(r, a); + r->magnitude = 1; + r->normalized = 1; + secp256k1_fe_verify(r); +} #endif /* defined(VERIFY) */ #endif /* SECP256K1_FIELD_IMPL_H */ From d5aa2f035802047c45605bfa69fb467000e9288f Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 28 Jan 2022 19:20:51 -0500 Subject: [PATCH 077/100] Abstract out verify logic for fe_inv{,_var} --- src/field.h | 16 +++++++++++++--- src/field_10x26_impl.h | 28 ++++------------------------ src/field_5x52_impl.h | 28 ++++------------------------ src/field_impl.h | 22 ++++++++++++++++++++++ 4 files changed, 43 insertions(+), 51 deletions(-) diff --git a/src/field.h b/src/field.h index cb330635dc..953919d9a3 100644 --- a/src/field.h +++ b/src/field.h @@ -95,6 +95,8 @@ static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST( # define secp256k1_fe_cmov secp256k1_fe_impl_cmov # define secp256k1_fe_to_storage secp256k1_fe_impl_to_storage # define secp256k1_fe_from_storage secp256k1_fe_impl_from_storage +# define secp256k1_fe_inv secp256k1_fe_impl_inv +# define secp256k1_fe_inv_var secp256k1_fe_impl_inv_var #endif /* !defined(VERIFY) */ /** Normalize a field element. @@ -258,11 +260,19 @@ static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a); */ static int secp256k1_fe_sqrt(secp256k1_fe * SECP256K1_RESTRICT r, const secp256k1_fe * SECP256K1_RESTRICT a); -/** Sets a field element to be the (modular) inverse of another. Requires the input's magnitude to be - * at most 8. The output magnitude is 1 (but not guaranteed to be normalized). */ +/** Compute the modular inverse of a field element. + * + * On input, a must be a valid field element; r need not be initialized. + * Performs {r = a**(p-2)} (which maps 0 to 0, and every other element to its + * inverse). + * On output, r will have magnitude (a.magnitude != 0) and be normalized. + */ static void secp256k1_fe_inv(secp256k1_fe *r, const secp256k1_fe *a); -/** Potentially faster version of secp256k1_fe_inv, without constant-time guarantee. */ +/** Compute the modular inverse of a field element, without constant-time guarantee. + * + * Behaves identically to secp256k1_fe_inv, but is not constant-time in a. + */ static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *a); /** Convert a field element to secp256k1_fe_storage. diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h index 55d152ec26..d7b30cc87d 100644 --- a/src/field_10x26_impl.h +++ b/src/field_10x26_impl.h @@ -1197,12 +1197,6 @@ static void secp256k1_fe_from_signed30(secp256k1_fe *r, const secp256k1_modinv32 r->n[7] = (a6 >> 2 ) & M26; r->n[8] = (a6 >> 28 | a7 << 2) & M26; r->n[9] = (a7 >> 24 | a8 << 6); - -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 1; - secp256k1_fe_verify(r); -#endif } static void secp256k1_fe_to_signed30(secp256k1_modinv32_signed30 *r, const secp256k1_fe *a) { @@ -1210,10 +1204,6 @@ static void secp256k1_fe_to_signed30(secp256k1_modinv32_signed30 *r, const secp2 const uint64_t a0 = a->n[0], a1 = a->n[1], a2 = a->n[2], a3 = a->n[3], a4 = a->n[4], a5 = a->n[5], a6 = a->n[6], a7 = a->n[7], a8 = a->n[8], a9 = a->n[9]; -#ifdef VERIFY - VERIFY_CHECK(a->normalized); -#endif - r->v[0] = (a0 | a1 << 26) & M30; r->v[1] = (a1 >> 4 | a2 << 22) & M30; r->v[2] = (a2 >> 8 | a3 << 18) & M30; @@ -1231,34 +1221,24 @@ static const secp256k1_modinv32_modinfo secp256k1_const_modinfo_fe = { 0x2DDACACFL }; -static void secp256k1_fe_inv(secp256k1_fe *r, const secp256k1_fe *x) { - secp256k1_fe tmp; +static void secp256k1_fe_impl_inv(secp256k1_fe *r, const secp256k1_fe *x) { + secp256k1_fe tmp = *x; secp256k1_modinv32_signed30 s; - tmp = *x; secp256k1_fe_normalize(&tmp); secp256k1_fe_to_signed30(&s, &tmp); secp256k1_modinv32(&s, &secp256k1_const_modinfo_fe); secp256k1_fe_from_signed30(r, &s); - -#ifdef VERIFY - VERIFY_CHECK(secp256k1_fe_normalizes_to_zero(r) == secp256k1_fe_normalizes_to_zero(&tmp)); -#endif } -static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *x) { - secp256k1_fe tmp; +static void secp256k1_fe_impl_inv_var(secp256k1_fe *r, const secp256k1_fe *x) { + secp256k1_fe tmp = *x; secp256k1_modinv32_signed30 s; - tmp = *x; secp256k1_fe_normalize_var(&tmp); secp256k1_fe_to_signed30(&s, &tmp); secp256k1_modinv32_var(&s, &secp256k1_const_modinfo_fe); secp256k1_fe_from_signed30(r, &s); - -#ifdef VERIFY - VERIFY_CHECK(secp256k1_fe_normalizes_to_zero(r) == secp256k1_fe_normalizes_to_zero(&tmp)); -#endif } static int secp256k1_fe_is_square_var(const secp256k1_fe *x) { diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h index 1946fbb88b..e056cc2620 100644 --- a/src/field_5x52_impl.h +++ b/src/field_5x52_impl.h @@ -492,22 +492,12 @@ static void secp256k1_fe_from_signed62(secp256k1_fe *r, const secp256k1_modinv64 r->n[2] = (a1 >> 42 | a2 << 20) & M52; r->n[3] = (a2 >> 32 | a3 << 30) & M52; r->n[4] = (a3 >> 22 | a4 << 40); - -#ifdef VERIFY - r->magnitude = 1; - r->normalized = 1; - secp256k1_fe_verify(r); -#endif } static void secp256k1_fe_to_signed62(secp256k1_modinv64_signed62 *r, const secp256k1_fe *a) { const uint64_t M62 = UINT64_MAX >> 2; const uint64_t a0 = a->n[0], a1 = a->n[1], a2 = a->n[2], a3 = a->n[3], a4 = a->n[4]; -#ifdef VERIFY - VERIFY_CHECK(a->normalized); -#endif - r->v[0] = (a0 | a1 << 52) & M62; r->v[1] = (a1 >> 10 | a2 << 42) & M62; r->v[2] = (a2 >> 20 | a3 << 32) & M62; @@ -520,34 +510,24 @@ static const secp256k1_modinv64_modinfo secp256k1_const_modinfo_fe = { 0x27C7F6E22DDACACFLL }; -static void secp256k1_fe_inv(secp256k1_fe *r, const secp256k1_fe *x) { - secp256k1_fe tmp; +static void secp256k1_fe_impl_inv(secp256k1_fe *r, const secp256k1_fe *x) { + secp256k1_fe tmp = *x; secp256k1_modinv64_signed62 s; - tmp = *x; secp256k1_fe_normalize(&tmp); secp256k1_fe_to_signed62(&s, &tmp); secp256k1_modinv64(&s, &secp256k1_const_modinfo_fe); secp256k1_fe_from_signed62(r, &s); - -#ifdef VERIFY - VERIFY_CHECK(secp256k1_fe_normalizes_to_zero(r) == secp256k1_fe_normalizes_to_zero(&tmp)); -#endif } -static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *x) { - secp256k1_fe tmp; +static void secp256k1_fe_impl_inv_var(secp256k1_fe *r, const secp256k1_fe *x) { + secp256k1_fe tmp = *x; secp256k1_modinv64_signed62 s; - tmp = *x; secp256k1_fe_normalize_var(&tmp); secp256k1_fe_to_signed62(&s, &tmp); secp256k1_modinv64_var(&s, &secp256k1_const_modinfo_fe); secp256k1_fe_from_signed62(r, &s); - -#ifdef VERIFY - VERIFY_CHECK(secp256k1_fe_normalizes_to_zero(r) == secp256k1_fe_normalizes_to_zero(&tmp)); -#endif } static int secp256k1_fe_is_square_var(const secp256k1_fe *x) { diff --git a/src/field_impl.h b/src/field_impl.h index 0e1c7630be..3c03e26352 100644 --- a/src/field_impl.h +++ b/src/field_impl.h @@ -351,6 +351,28 @@ SECP256K1_INLINE static void secp256k1_fe_from_storage(secp256k1_fe *r, const se r->normalized = 1; secp256k1_fe_verify(r); } + +static void secp256k1_fe_impl_inv(secp256k1_fe *r, const secp256k1_fe *x); +SECP256K1_INLINE static void secp256k1_fe_inv(secp256k1_fe *r, const secp256k1_fe *x) { + int input_is_zero = secp256k1_fe_normalizes_to_zero(x); + secp256k1_fe_verify(x); + secp256k1_fe_impl_inv(r, x); + r->magnitude = x->magnitude > 0; + r->normalized = 1; + VERIFY_CHECK(secp256k1_fe_normalizes_to_zero(r) == input_is_zero); + secp256k1_fe_verify(r); +} + +static void secp256k1_fe_impl_inv_var(secp256k1_fe *r, const secp256k1_fe *x); +SECP256K1_INLINE static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *x) { + int input_is_zero = secp256k1_fe_normalizes_to_zero(x); + secp256k1_fe_verify(x); + secp256k1_fe_impl_inv_var(r, x); + r->magnitude = x->magnitude > 0; + r->normalized = 1; + VERIFY_CHECK(secp256k1_fe_normalizes_to_zero(r) == input_is_zero); + secp256k1_fe_verify(r); +} #endif /* defined(VERIFY) */ #endif /* SECP256K1_FIELD_IMPL_H */ From 283cd80ab471bccb995925eb55865f04e38566f4 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Wed, 8 Jun 2022 15:04:49 -0400 Subject: [PATCH 078/100] Abstract out verify logic for fe_get_bounds --- src/field.h | 6 ++++-- src/field_10x26_impl.h | 9 +-------- src/field_5x52_impl.h | 9 +-------- src/field_impl.h | 11 +++++++++++ 4 files changed, 17 insertions(+), 18 deletions(-) diff --git a/src/field.h b/src/field.h index 953919d9a3..4b23333eb0 100644 --- a/src/field.h +++ b/src/field.h @@ -97,6 +97,7 @@ static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST( # define secp256k1_fe_from_storage secp256k1_fe_impl_from_storage # define secp256k1_fe_inv secp256k1_fe_impl_inv # define secp256k1_fe_inv_var secp256k1_fe_impl_inv_var +# define secp256k1_fe_get_bounds secp256k1_fe_impl_get_bounds #endif /* !defined(VERIFY) */ /** Normalize a field element. @@ -306,8 +307,9 @@ static void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag); * The output is not guaranteed to be normalized, regardless of the input. */ static void secp256k1_fe_half(secp256k1_fe *r); -/** Sets each limb of 'r' to its upper bound at magnitude 'm'. The output will also have its - * magnitude set to 'm' and is normalized if (and only if) 'm' is zero. */ +/** Sets r to a field element with magnitude m, normalized if (and only if) m==0. + * The value is chosen so that it is likely to trigger edge cases related to + * internal overflows. */ static void secp256k1_fe_get_bounds(secp256k1_fe *r, int m); /** Determine whether a is a square (modulo p). */ diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h index d7b30cc87d..39588c0bf9 100644 --- a/src/field_10x26_impl.h +++ b/src/field_10x26_impl.h @@ -38,9 +38,7 @@ static void secp256k1_fe_impl_verify(const secp256k1_fe *a) { } #endif -static void secp256k1_fe_get_bounds(secp256k1_fe *r, int m) { - VERIFY_CHECK(m >= 0); - VERIFY_CHECK(m <= 2048); +static void secp256k1_fe_impl_get_bounds(secp256k1_fe *r, int m) { r->n[0] = 0x3FFFFFFUL * 2 * m; r->n[1] = 0x3FFFFFFUL * 2 * m; r->n[2] = 0x3FFFFFFUL * 2 * m; @@ -51,11 +49,6 @@ static void secp256k1_fe_get_bounds(secp256k1_fe *r, int m) { r->n[7] = 0x3FFFFFFUL * 2 * m; r->n[8] = 0x3FFFFFFUL * 2 * m; r->n[9] = 0x03FFFFFUL * 2 * m; -#ifdef VERIFY - r->magnitude = m; - r->normalized = (m == 0); - secp256k1_fe_verify(r); -#endif } static void secp256k1_fe_impl_normalize(secp256k1_fe *r) { diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h index e056cc2620..d9d4e1a7bd 100644 --- a/src/field_5x52_impl.h +++ b/src/field_5x52_impl.h @@ -37,19 +37,12 @@ static void secp256k1_fe_impl_verify(const secp256k1_fe *a) { } #endif -static void secp256k1_fe_get_bounds(secp256k1_fe *r, int m) { - VERIFY_CHECK(m >= 0); - VERIFY_CHECK(m <= 2048); +static void secp256k1_fe_impl_get_bounds(secp256k1_fe *r, int m) { r->n[0] = 0xFFFFFFFFFFFFFULL * 2 * m; r->n[1] = 0xFFFFFFFFFFFFFULL * 2 * m; r->n[2] = 0xFFFFFFFFFFFFFULL * 2 * m; r->n[3] = 0xFFFFFFFFFFFFFULL * 2 * m; r->n[4] = 0x0FFFFFFFFFFFFULL * 2 * m; -#ifdef VERIFY - r->magnitude = m; - r->normalized = (m == 0); - secp256k1_fe_verify(r); -#endif } static void secp256k1_fe_impl_normalize(secp256k1_fe *r) { diff --git a/src/field_impl.h b/src/field_impl.h index 3c03e26352..0eac34d10f 100644 --- a/src/field_impl.h +++ b/src/field_impl.h @@ -373,6 +373,17 @@ SECP256K1_INLINE static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256 VERIFY_CHECK(secp256k1_fe_normalizes_to_zero(r) == input_is_zero); secp256k1_fe_verify(r); } + +static void secp256k1_fe_impl_get_bounds(secp256k1_fe* r, int m); +SECP256K1_INLINE static void secp256k1_fe_get_bounds(secp256k1_fe* r, int m) { + VERIFY_CHECK(m >= 0); + VERIFY_CHECK(m <= 32); + secp256k1_fe_impl_get_bounds(r, m); + r->magnitude = m; + r->normalized = (m == 0); + secp256k1_fe_verify(r); +} + #endif /* defined(VERIFY) */ #endif /* SECP256K1_FIELD_IMPL_H */ From 89e324c6b9d1c74d3636b4ef5b1e5404e3e2053b Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Thu, 17 Nov 2022 11:28:49 -0500 Subject: [PATCH 079/100] Abstract out verify logic for fe_half --- src/field.h | 10 +++++++--- src/field_10x26_impl.h | 17 +++-------------- src/field_5x52_impl.h | 17 +++-------------- src/field_impl.h | 10 ++++++++++ 4 files changed, 23 insertions(+), 31 deletions(-) diff --git a/src/field.h b/src/field.h index 4b23333eb0..c20638e45e 100644 --- a/src/field.h +++ b/src/field.h @@ -98,6 +98,7 @@ static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST( # define secp256k1_fe_inv secp256k1_fe_impl_inv # define secp256k1_fe_inv_var secp256k1_fe_impl_inv_var # define secp256k1_fe_get_bounds secp256k1_fe_impl_get_bounds +# define secp256k1_fe_half secp256k1_fe_impl_half #endif /* !defined(VERIFY) */ /** Normalize a field element. @@ -302,9 +303,12 @@ static void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_f */ static void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag); -/** Halves the value of a field element modulo the field prime. Constant-time. - * For an input magnitude 'm', the output magnitude is set to 'floor(m/2) + 1'. - * The output is not guaranteed to be normalized, regardless of the input. */ +/** Halve the value of a field element modulo the field prime in constant-time. + * + * On input, r must be a valid field element. + * On output, r will be normalized and have magnitude floor(m/2) + 1 where m is + * the magnitude of r on input. + */ static void secp256k1_fe_half(secp256k1_fe *r); /** Sets r to a field element with magnitude m, normalized if (and only if) m==0. diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h index 39588c0bf9..ec53165e88 100644 --- a/src/field_10x26_impl.h +++ b/src/field_10x26_impl.h @@ -1046,17 +1046,12 @@ SECP256K1_INLINE static void secp256k1_fe_impl_cmov(secp256k1_fe *r, const secp2 r->n[9] = (r->n[9] & mask0) | (a->n[9] & mask1); } -static SECP256K1_INLINE void secp256k1_fe_half(secp256k1_fe *r) { +static SECP256K1_INLINE void secp256k1_fe_impl_half(secp256k1_fe *r) { uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4], t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9]; uint32_t one = (uint32_t)1; uint32_t mask = -(t0 & one) >> 6; -#ifdef VERIFY - secp256k1_fe_verify(r); - VERIFY_CHECK(r->magnitude < 32); -#endif - /* Bounds analysis (over the rationals). * * Let m = r->magnitude @@ -1103,10 +1098,8 @@ static SECP256K1_INLINE void secp256k1_fe_half(secp256k1_fe *r) { * * Current bounds: t0..t8 <= C * (m/2 + 1/2) * t9 <= D * (m/2 + 1/4) - */ - -#ifdef VERIFY - /* Therefore the output magnitude (M) has to be set such that: + * + * Therefore the output magnitude (M) has to be set such that: * t0..t8: C * M >= C * (m/2 + 1/2) * t9: D * M >= D * (m/2 + 1/4) * @@ -1116,10 +1109,6 @@ static SECP256K1_INLINE void secp256k1_fe_half(secp256k1_fe *r) { * and since we want the smallest such integer value for M: * M == floor(m/2) + 1 */ - r->magnitude = (r->magnitude >> 1) + 1; - r->normalized = 0; - secp256k1_fe_verify(r); -#endif } static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag) { diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h index d9d4e1a7bd..06a2e379ab 100644 --- a/src/field_5x52_impl.h +++ b/src/field_5x52_impl.h @@ -375,16 +375,11 @@ SECP256K1_INLINE static void secp256k1_fe_impl_cmov(secp256k1_fe *r, const secp2 r->n[4] = (r->n[4] & mask0) | (a->n[4] & mask1); } -static SECP256K1_INLINE void secp256k1_fe_half(secp256k1_fe *r) { +static SECP256K1_INLINE void secp256k1_fe_impl_half(secp256k1_fe *r) { uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4]; uint64_t one = (uint64_t)1; uint64_t mask = -(t0 & one) >> 12; -#ifdef VERIFY - secp256k1_fe_verify(r); - VERIFY_CHECK(r->magnitude < 32); -#endif - /* Bounds analysis (over the rationals). * * Let m = r->magnitude @@ -421,10 +416,8 @@ static SECP256K1_INLINE void secp256k1_fe_half(secp256k1_fe *r) { * * Current bounds: t0..t3 <= C * (m/2 + 1/2) * t4 <= D * (m/2 + 1/4) - */ - -#ifdef VERIFY - /* Therefore the output magnitude (M) has to be set such that: + * + * Therefore the output magnitude (M) has to be set such that: * t0..t3: C * M >= C * (m/2 + 1/2) * t4: D * M >= D * (m/2 + 1/4) * @@ -434,10 +427,6 @@ static SECP256K1_INLINE void secp256k1_fe_half(secp256k1_fe *r) { * and since we want the smallest such integer value for M: * M == floor(m/2) + 1 */ - r->magnitude = (r->magnitude >> 1) + 1; - r->normalized = 0; - secp256k1_fe_verify(r); -#endif } static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag) { diff --git a/src/field_impl.h b/src/field_impl.h index 0eac34d10f..8dbc765f73 100644 --- a/src/field_impl.h +++ b/src/field_impl.h @@ -384,6 +384,16 @@ SECP256K1_INLINE static void secp256k1_fe_get_bounds(secp256k1_fe* r, int m) { secp256k1_fe_verify(r); } +static void secp256k1_fe_impl_half(secp256k1_fe *r); +SECP256K1_INLINE static void secp256k1_fe_half(secp256k1_fe *r) { + secp256k1_fe_verify(r); + VERIFY_CHECK(r->magnitude < 32); + secp256k1_fe_impl_half(r); + r->magnitude = (r->magnitude >> 1) + 1; + r->normalized = 0; + secp256k1_fe_verify(r); +} + #endif /* defined(VERIFY) */ #endif /* SECP256K1_FIELD_IMPL_H */ From 4371f98346b0a50c0a77e93948fe5e21d9346d06 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Thu, 11 May 2023 03:05:35 -0400 Subject: [PATCH 080/100] Abstract out verify logic for fe_add_int --- src/field.h | 7 ++++++- src/field_10x26_impl.h | 10 +--------- src/field_5x52_impl.h | 10 +--------- src/field_impl.h | 10 ++++++++++ 4 files changed, 18 insertions(+), 19 deletions(-) diff --git a/src/field.h b/src/field.h index c20638e45e..a515f38095 100644 --- a/src/field.h +++ b/src/field.h @@ -99,6 +99,7 @@ static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST( # define secp256k1_fe_inv_var secp256k1_fe_impl_inv_var # define secp256k1_fe_get_bounds secp256k1_fe_impl_get_bounds # define secp256k1_fe_half secp256k1_fe_impl_half +# define secp256k1_fe_add_int secp256k1_fe_impl_add_int #endif /* !defined(VERIFY) */ /** Normalize a field element. @@ -213,7 +214,11 @@ static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a); */ static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m); -/** Adds a small integer (up to 0x7FFF) to r. The resulting magnitude increases by one. */ +/** Add a small integer to a field element. + * + * Performs {r += a}. The magnitude of r increases by 1, and normalized is cleared. + * a must be in range [0,0xFFFF]. + */ static void secp256k1_fe_add_int(secp256k1_fe *r, int a); /** Multiply a field element with a small integer. diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h index ec53165e88..80f32aa460 100644 --- a/src/field_10x26_impl.h +++ b/src/field_10x26_impl.h @@ -389,16 +389,8 @@ SECP256K1_INLINE static void secp256k1_fe_impl_add(secp256k1_fe *r, const secp25 r->n[9] += a->n[9]; } -SECP256K1_INLINE static void secp256k1_fe_add_int(secp256k1_fe *r, int a) { - secp256k1_fe_verify(r); - VERIFY_CHECK(a >= 0); - VERIFY_CHECK(a <= 0x7FFF); +SECP256K1_INLINE static void secp256k1_fe_impl_add_int(secp256k1_fe *r, int a) { r->n[0] += a; -#ifdef VERIFY - r->magnitude += 1; - r->normalized = 0; - secp256k1_fe_verify(r); -#endif } #if defined(USE_EXTERNAL_ASM) diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h index 06a2e379ab..a9a436dec0 100644 --- a/src/field_5x52_impl.h +++ b/src/field_5x52_impl.h @@ -334,16 +334,8 @@ SECP256K1_INLINE static void secp256k1_fe_impl_mul_int(secp256k1_fe *r, int a) { r->n[4] *= a; } -SECP256K1_INLINE static void secp256k1_fe_add_int(secp256k1_fe *r, int a) { - secp256k1_fe_verify(r); - VERIFY_CHECK(a >= 0); - VERIFY_CHECK(a <= 0x7FFF); +SECP256K1_INLINE static void secp256k1_fe_impl_add_int(secp256k1_fe *r, int a) { r->n[0] += a; -#ifdef VERIFY - r->magnitude += 1; - r->normalized = 0; - secp256k1_fe_verify(r); -#endif } SECP256K1_INLINE static void secp256k1_fe_impl_add(secp256k1_fe *r, const secp256k1_fe *a) { diff --git a/src/field_impl.h b/src/field_impl.h index 8dbc765f73..0d46b313d5 100644 --- a/src/field_impl.h +++ b/src/field_impl.h @@ -220,6 +220,16 @@ SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe *r, int a) { secp256k1_fe_verify(r); } +static void secp256k1_fe_impl_add_int(secp256k1_fe *r, int a); +SECP256K1_INLINE static void secp256k1_fe_add_int(secp256k1_fe *r, int a) { + VERIFY_CHECK(0 <= a && a <= 0x7FFF); + secp256k1_fe_verify(r); + secp256k1_fe_impl_add_int(r, a); + r->magnitude += 1; + r->normalized = 0; + secp256k1_fe_verify(r); +} + static void secp256k1_fe_impl_clear(secp256k1_fe *a); SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe *a) { a->magnitude = 0; From 4e176ad5b94f989d5e2c6cdf9b2761a6f6a971e5 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Thu, 11 May 2023 03:16:00 -0400 Subject: [PATCH 081/100] Abstract out verify logic for fe_is_square_var --- src/field.h | 6 +++++- src/field_10x26_impl.h | 6 +----- src/field_5x52_impl.h | 6 +----- src/field_impl.h | 11 +++++++++++ 4 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/field.h b/src/field.h index a515f38095..2c8fbc28e3 100644 --- a/src/field.h +++ b/src/field.h @@ -100,6 +100,7 @@ static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST( # define secp256k1_fe_get_bounds secp256k1_fe_impl_get_bounds # define secp256k1_fe_half secp256k1_fe_impl_half # define secp256k1_fe_add_int secp256k1_fe_impl_add_int +# define secp256k1_fe_is_square_var secp256k1_fe_impl_is_square_var #endif /* !defined(VERIFY) */ /** Normalize a field element. @@ -321,7 +322,10 @@ static void secp256k1_fe_half(secp256k1_fe *r); * internal overflows. */ static void secp256k1_fe_get_bounds(secp256k1_fe *r, int m); -/** Determine whether a is a square (modulo p). */ +/** Determine whether a is a square (modulo p). + * + * On input, a must be a valid field element. + */ static int secp256k1_fe_is_square_var(const secp256k1_fe *a); /** Check invariants on a field element (no-op unless VERIFY is enabled). */ diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h index 80f32aa460..946c95fb2f 100644 --- a/src/field_10x26_impl.h +++ b/src/field_10x26_impl.h @@ -1215,7 +1215,7 @@ static void secp256k1_fe_impl_inv_var(secp256k1_fe *r, const secp256k1_fe *x) { secp256k1_fe_from_signed30(r, &s); } -static int secp256k1_fe_is_square_var(const secp256k1_fe *x) { +static int secp256k1_fe_impl_is_square_var(const secp256k1_fe *x) { secp256k1_fe tmp; secp256k1_modinv32_signed30 s; int jac, ret; @@ -1233,10 +1233,6 @@ static int secp256k1_fe_is_square_var(const secp256k1_fe *x) { secp256k1_fe dummy; ret = secp256k1_fe_sqrt(&dummy, &tmp); } else { -#ifdef VERIFY - secp256k1_fe dummy; - VERIFY_CHECK(jac == 2*secp256k1_fe_sqrt(&dummy, &tmp) - 1); -#endif ret = jac >= 0; } return ret; diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h index a9a436dec0..f947903675 100644 --- a/src/field_5x52_impl.h +++ b/src/field_5x52_impl.h @@ -504,7 +504,7 @@ static void secp256k1_fe_impl_inv_var(secp256k1_fe *r, const secp256k1_fe *x) { secp256k1_fe_from_signed62(r, &s); } -static int secp256k1_fe_is_square_var(const secp256k1_fe *x) { +static int secp256k1_fe_impl_is_square_var(const secp256k1_fe *x) { secp256k1_fe tmp; secp256k1_modinv64_signed62 s; int jac, ret; @@ -522,10 +522,6 @@ static int secp256k1_fe_is_square_var(const secp256k1_fe *x) { secp256k1_fe dummy; ret = secp256k1_fe_sqrt(&dummy, &tmp); } else { -#ifdef VERIFY - secp256k1_fe dummy; - VERIFY_CHECK(jac == 2*secp256k1_fe_sqrt(&dummy, &tmp) - 1); -#endif ret = jac >= 0; } return ret; diff --git a/src/field_impl.h b/src/field_impl.h index 0d46b313d5..187ffc8d8b 100644 --- a/src/field_impl.h +++ b/src/field_impl.h @@ -384,6 +384,17 @@ SECP256K1_INLINE static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256 secp256k1_fe_verify(r); } +static int secp256k1_fe_impl_is_square_var(const secp256k1_fe *x); +SECP256K1_INLINE static int secp256k1_fe_is_square_var(const secp256k1_fe *x) { + int ret; + secp256k1_fe tmp = *x, sqrt; + secp256k1_fe_verify(x); + ret = secp256k1_fe_impl_is_square_var(x); + secp256k1_fe_normalize_weak(&tmp); + VERIFY_CHECK(ret == secp256k1_fe_sqrt(&sqrt, &tmp)); + return ret; +} + static void secp256k1_fe_impl_get_bounds(secp256k1_fe* r, int m); SECP256K1_INLINE static void secp256k1_fe_get_bounds(secp256k1_fe* r, int m) { VERIFY_CHECK(m >= 0); From 7fc642fa25ad03ebd95cfe237b625dfb6dfdfa94 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Thu, 11 May 2023 04:42:09 -0400 Subject: [PATCH 082/100] Simplify secp256k1_fe_{impl_,}verify --- src/field_10x26_impl.h | 27 +++++++++++++-------------- src/field_5x52_impl.h | 17 ++++++++--------- src/field_impl.h | 7 +++---- 3 files changed, 24 insertions(+), 27 deletions(-) diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h index 946c95fb2f..3f719c161f 100644 --- a/src/field_10x26_impl.h +++ b/src/field_10x26_impl.h @@ -15,26 +15,25 @@ #ifdef VERIFY static void secp256k1_fe_impl_verify(const secp256k1_fe *a) { const uint32_t *d = a->n; - int m = a->normalized ? 1 : 2 * a->magnitude, r = 1; - r &= (d[0] <= 0x3FFFFFFUL * m); - r &= (d[1] <= 0x3FFFFFFUL * m); - r &= (d[2] <= 0x3FFFFFFUL * m); - r &= (d[3] <= 0x3FFFFFFUL * m); - r &= (d[4] <= 0x3FFFFFFUL * m); - r &= (d[5] <= 0x3FFFFFFUL * m); - r &= (d[6] <= 0x3FFFFFFUL * m); - r &= (d[7] <= 0x3FFFFFFUL * m); - r &= (d[8] <= 0x3FFFFFFUL * m); - r &= (d[9] <= 0x03FFFFFUL * m); + int m = a->normalized ? 1 : 2 * a->magnitude; + VERIFY_CHECK(d[0] <= 0x3FFFFFFUL * m); + VERIFY_CHECK(d[1] <= 0x3FFFFFFUL * m); + VERIFY_CHECK(d[2] <= 0x3FFFFFFUL * m); + VERIFY_CHECK(d[3] <= 0x3FFFFFFUL * m); + VERIFY_CHECK(d[4] <= 0x3FFFFFFUL * m); + VERIFY_CHECK(d[5] <= 0x3FFFFFFUL * m); + VERIFY_CHECK(d[6] <= 0x3FFFFFFUL * m); + VERIFY_CHECK(d[7] <= 0x3FFFFFFUL * m); + VERIFY_CHECK(d[8] <= 0x3FFFFFFUL * m); + VERIFY_CHECK(d[9] <= 0x03FFFFFUL * m); if (a->normalized) { - if (r && (d[9] == 0x03FFFFFUL)) { + if (d[9] == 0x03FFFFFUL) { uint32_t mid = d[8] & d[7] & d[6] & d[5] & d[4] & d[3] & d[2]; if (mid == 0x3FFFFFFUL) { - r &= ((d[1] + 0x40UL + ((d[0] + 0x3D1UL) >> 26)) <= 0x3FFFFFFUL); + VERIFY_CHECK((d[1] + 0x40UL + ((d[0] + 0x3D1UL) >> 26)) <= 0x3FFFFFFUL); } } } - VERIFY_CHECK(r == 1); } #endif diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h index f947903675..a44a64b5a1 100644 --- a/src/field_5x52_impl.h +++ b/src/field_5x52_impl.h @@ -21,19 +21,18 @@ #ifdef VERIFY static void secp256k1_fe_impl_verify(const secp256k1_fe *a) { const uint64_t *d = a->n; - int m = a->normalized ? 1 : 2 * a->magnitude, r = 1; + int m = a->normalized ? 1 : 2 * a->magnitude; /* secp256k1 'p' value defined in "Standards for Efficient Cryptography" (SEC2) 2.7.1. */ - r &= (d[0] <= 0xFFFFFFFFFFFFFULL * m); - r &= (d[1] <= 0xFFFFFFFFFFFFFULL * m); - r &= (d[2] <= 0xFFFFFFFFFFFFFULL * m); - r &= (d[3] <= 0xFFFFFFFFFFFFFULL * m); - r &= (d[4] <= 0x0FFFFFFFFFFFFULL * m); + VERIFY_CHECK(d[0] <= 0xFFFFFFFFFFFFFULL * m); + VERIFY_CHECK(d[1] <= 0xFFFFFFFFFFFFFULL * m); + VERIFY_CHECK(d[2] <= 0xFFFFFFFFFFFFFULL * m); + VERIFY_CHECK(d[3] <= 0xFFFFFFFFFFFFFULL * m); + VERIFY_CHECK(d[4] <= 0x0FFFFFFFFFFFFULL * m); if (a->normalized) { - if (r && (d[4] == 0x0FFFFFFFFFFFFULL) && ((d[3] & d[2] & d[1]) == 0xFFFFFFFFFFFFFULL)) { - r &= (d[0] < 0xFFFFEFFFFFC2FULL); + if ((d[4] == 0x0FFFFFFFFFFFFULL) && ((d[3] & d[2] & d[1]) == 0xFFFFFFFFFFFFFULL)) { + VERIFY_CHECK(d[0] < 0xFFFFEFFFFFC2FULL); } } - VERIFY_CHECK(r == 1); } #endif diff --git a/src/field_impl.h b/src/field_impl.h index 187ffc8d8b..c082d8f553 100644 --- a/src/field_impl.h +++ b/src/field_impl.h @@ -163,12 +163,11 @@ static void secp256k1_fe_verify(const secp256k1_fe *a) { (void)a; } static void secp256k1_fe_impl_verify(const secp256k1_fe *a); static void secp256k1_fe_verify(const secp256k1_fe *a) { /* Magnitude between 0 and 32. */ - int r = (a->magnitude >= 0) & (a->magnitude <= 32); + VERIFY_CHECK((a->magnitude >= 0) && (a->magnitude <= 32)); /* Normalized is 0 or 1. */ - r &= (a->normalized == 0) | (a->normalized == 1); + VERIFY_CHECK((a->normalized == 0) || (a->normalized == 1)); /* If normalized, magnitude must be 0 or 1. */ - if (a->normalized) r &= (a->magnitude <= 1); - VERIFY_CHECK(r == 1); + if (a->normalized) VERIFY_CHECK(a->magnitude <= 1); /* Invoke implementation-specific checks. */ secp256k1_fe_impl_verify(a); } From 712e7f8722eba5dec2bc6b37d75aadeb6f6e633b Mon Sep 17 00:00:00 2001 From: Jonas Nick Date: Thu, 11 May 2023 13:24:37 +0000 Subject: [PATCH 083/100] Remove unused scratch space from API --- include/secp256k1.h | 36 ------------------------------------ src/scratch.h | 2 ++ src/secp256k1.c | 4 ++-- 3 files changed, 4 insertions(+), 38 deletions(-) diff --git a/include/secp256k1.h b/include/secp256k1.h index a7a2be7a3a..d5450e2998 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 @@ -385,29 +372,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: an existing 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: a secp256k1 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 9dcb7581f6..6164330b39 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 7af333ca90..086cbc85cd 100644 --- a/src/secp256k1.c +++ b/src/secp256k1.c @@ -219,12 +219,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 5fb336f9ce7d287015ada5d1d6be35d63469c9a4 Mon Sep 17 00:00:00 2001 From: Tim Ruffing Date: Wed, 10 May 2023 15:19:38 +0200 Subject: [PATCH 084/100] ct: Use volatile trick in scalar_cond_negate --- src/scalar_4x64_impl.h | 3 ++- src/scalar_8x32_impl.h | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/scalar_4x64_impl.h b/src/scalar_4x64_impl.h index 88981519b6..2a5584ea45 100644 --- a/src/scalar_4x64_impl.h +++ b/src/scalar_4x64_impl.h @@ -189,7 +189,8 @@ static int secp256k1_scalar_is_high(const secp256k1_scalar *a) { static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) { /* If we are flag = 0, mask = 00...00 and this is a no-op; * if we are flag = 1, mask = 11...11 and this is identical to secp256k1_scalar_negate */ - uint64_t mask = !flag - 1; + volatile int vflag = flag; + uint64_t mask = -vflag; uint64_t nonzero = (secp256k1_scalar_is_zero(r) != 0) - 1; secp256k1_uint128 t; secp256k1_u128_from_u64(&t, r->d[0] ^ mask); diff --git a/src/scalar_8x32_impl.h b/src/scalar_8x32_impl.h index 94ae22f75f..f9889d5372 100644 --- a/src/scalar_8x32_impl.h +++ b/src/scalar_8x32_impl.h @@ -242,7 +242,8 @@ static int secp256k1_scalar_is_high(const secp256k1_scalar *a) { static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) { /* If we are flag = 0, mask = 00...00 and this is a no-op; * if we are flag = 1, mask = 11...11 and this is identical to secp256k1_scalar_negate */ - uint32_t mask = !flag - 1; + volatile int vflag = flag; + uint32_t mask = -vflag; uint32_t nonzero = 0xFFFFFFFFUL * (secp256k1_scalar_is_zero(r) == 0); uint64_t t = (uint64_t)(r->d[0] ^ mask) + ((SECP256K1_N_0 + 1) & mask); r->d[0] = t & nonzero; t >>= 32; From 17fa21733aae97bf671fede3ce528c7a3b2f5f14 Mon Sep 17 00:00:00 2001 From: Tim Ruffing Date: Wed, 10 May 2023 16:25:37 +0200 Subject: [PATCH 085/100] ct: Be cautious and use volatile trick in more "conditional" paths - secp256k1_scalar_cadd_bit - secp256k1_modinvXX_normalize_YY - secp256k1_modinvXX_divsteps_ZZ - ECMULT_CONST_TABLE_GET_GE Even though those code loations are not problematic right now (with current compilers). --- src/ecmult_const_impl.h | 2 +- src/modinv32_impl.h | 33 ++++++++++++++++++--------------- src/modinv64_impl.h | 31 +++++++++++++++++-------------- src/scalar_4x64_impl.h | 3 ++- src/scalar_8x32_impl.h | 3 ++- 5 files changed, 40 insertions(+), 32 deletions(-) diff --git a/src/ecmult_const_impl.h b/src/ecmult_const_impl.h index f2b6f48285..66082e66ec 100644 --- a/src/ecmult_const_impl.h +++ b/src/ecmult_const_impl.h @@ -29,7 +29,7 @@ static void secp256k1_ecmult_odd_multiples_table_globalz_windowa(secp256k1_ge *p #define ECMULT_CONST_TABLE_GET_GE(r,pre,n,w) do { \ int m = 0; \ /* Extract the sign-bit for a constant time absolute-value. */ \ - int mask = (n) >> (sizeof(n) * CHAR_BIT - 1); \ + int volatile mask = (n) >> (sizeof(n) * CHAR_BIT - 1); \ int abs_n = ((n) + mask) ^ mask; \ int idx_n = abs_n >> 1; \ secp256k1_fe neg_y; \ diff --git a/src/modinv32_impl.h b/src/modinv32_impl.h index 8e400b697b..0ea2699863 100644 --- a/src/modinv32_impl.h +++ b/src/modinv32_impl.h @@ -64,7 +64,7 @@ static void secp256k1_modinv32_normalize_30(secp256k1_modinv32_signed30 *r, int3 const int32_t M30 = (int32_t)(UINT32_MAX >> 2); int32_t r0 = r->v[0], r1 = r->v[1], r2 = r->v[2], r3 = r->v[3], r4 = r->v[4], r5 = r->v[5], r6 = r->v[6], r7 = r->v[7], r8 = r->v[8]; - int32_t cond_add, cond_negate; + volatile int32_t cond_add, cond_negate; #ifdef VERIFY /* Verify that all limbs are in range (-2^30,2^30). */ @@ -186,7 +186,8 @@ static int32_t secp256k1_modinv32_divsteps_30(int32_t zeta, uint32_t f0, uint32_ * being inside [-2^31,2^31) means that casting to signed works correctly. */ uint32_t u = 1, v = 0, q = 0, r = 1; - uint32_t c1, c2, f = f0, g = g0, x, y, z; + volatile uint32_t c1, c2; + uint32_t mask1, mask2, f = f0, g = g0, x, y, z; int i; for (i = 0; i < 30; ++i) { @@ -195,23 +196,25 @@ static int32_t secp256k1_modinv32_divsteps_30(int32_t zeta, uint32_t f0, uint32_ VERIFY_CHECK((q * f0 + r * g0) == g << i); /* Compute conditional masks for (zeta < 0) and for (g & 1). */ c1 = zeta >> 31; - c2 = -(g & 1); + mask1 = c1; + c2 = g & 1; + mask2 = -c2; /* Compute x,y,z, conditionally negated versions of f,u,v. */ - x = (f ^ c1) - c1; - y = (u ^ c1) - c1; - z = (v ^ c1) - c1; + x = (f ^ mask1) - mask1; + y = (u ^ mask1) - mask1; + z = (v ^ mask1) - mask1; /* Conditionally add x,y,z to g,q,r. */ - g += x & c2; - q += y & c2; - r += z & c2; - /* In what follows, c1 is a condition mask for (zeta < 0) and (g & 1). */ - c1 &= c2; + g += x & mask2; + q += y & mask2; + r += z & mask2; + /* In what follows, mask1 is a condition mask for (zeta < 0) and (g & 1). */ + mask1 &= mask2; /* Conditionally change zeta into -zeta-2 or zeta-1. */ - zeta = (zeta ^ c1) - 1; + zeta = (zeta ^ mask1) - 1; /* Conditionally add g,q,r to f,u,v. */ - f += g & c1; - u += q & c1; - v += r & c1; + f += g & mask1; + u += q & mask1; + v += r & mask1; /* Shifts */ g >>= 1; u <<= 1; diff --git a/src/modinv64_impl.h b/src/modinv64_impl.h index e33727d385..c7cef872a4 100644 --- a/src/modinv64_impl.h +++ b/src/modinv64_impl.h @@ -88,7 +88,7 @@ static int secp256k1_modinv64_det_check_pow2(const secp256k1_modinv64_trans2x2 * static void secp256k1_modinv64_normalize_62(secp256k1_modinv64_signed62 *r, int64_t sign, const secp256k1_modinv64_modinfo *modinfo) { const int64_t M62 = (int64_t)(UINT64_MAX >> 2); int64_t r0 = r->v[0], r1 = r->v[1], r2 = r->v[2], r3 = r->v[3], r4 = r->v[4]; - int64_t cond_add, cond_negate; + volatile int64_t cond_add, cond_negate; #ifdef VERIFY /* Verify that all limbs are in range (-2^62,2^62). */ @@ -175,7 +175,8 @@ static int64_t secp256k1_modinv64_divsteps_59(int64_t zeta, uint64_t f0, uint64_ * being inside [-2^63,2^63) means that casting to signed works correctly. */ uint64_t u = 8, v = 0, q = 0, r = 8; - uint64_t c1, c2, f = f0, g = g0, x, y, z; + volatile uint64_t c1, c2; + uint64_t mask1, mask2, f = f0, g = g0, x, y, z; int i; for (i = 3; i < 62; ++i) { @@ -184,23 +185,25 @@ static int64_t secp256k1_modinv64_divsteps_59(int64_t zeta, uint64_t f0, uint64_ VERIFY_CHECK((q * f0 + r * g0) == g << i); /* Compute conditional masks for (zeta < 0) and for (g & 1). */ c1 = zeta >> 63; - c2 = -(g & 1); + mask1 = c1; + c2 = g & 1; + mask2 = -c2; /* Compute x,y,z, conditionally negated versions of f,u,v. */ - x = (f ^ c1) - c1; - y = (u ^ c1) - c1; - z = (v ^ c1) - c1; + x = (f ^ mask1) - mask1; + y = (u ^ mask1) - mask1; + z = (v ^ mask1) - mask1; /* Conditionally add x,y,z to g,q,r. */ - g += x & c2; - q += y & c2; - r += z & c2; + g += x & mask2; + q += y & mask2; + r += z & mask2; /* In what follows, c1 is a condition mask for (zeta < 0) and (g & 1). */ - c1 &= c2; + mask1 &= mask2; /* Conditionally change zeta into -zeta-2 or zeta-1. */ - zeta = (zeta ^ c1) - 1; + zeta = (zeta ^ mask1) - 1; /* Conditionally add g,q,r to f,u,v. */ - f += g & c1; - u += q & c1; - v += r & c1; + f += g & mask1; + u += q & mask1; + v += r & mask1; /* Shifts */ g >>= 1; u <<= 1; diff --git a/src/scalar_4x64_impl.h b/src/scalar_4x64_impl.h index 2a5584ea45..e50ec3ae94 100644 --- a/src/scalar_4x64_impl.h +++ b/src/scalar_4x64_impl.h @@ -111,8 +111,9 @@ static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag) { secp256k1_uint128 t; + volatile int vflag = flag; VERIFY_CHECK(bit < 256); - bit += ((uint32_t) flag - 1) & 0x100; /* forcing (bit >> 6) > 3 makes this a noop */ + bit += ((uint32_t) vflag - 1) & 0x100; /* forcing (bit >> 6) > 3 makes this a noop */ secp256k1_u128_from_u64(&t, r->d[0]); secp256k1_u128_accum_u64(&t, ((uint64_t)((bit >> 6) == 0)) << (bit & 0x3F)); r->d[0] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64); diff --git a/src/scalar_8x32_impl.h b/src/scalar_8x32_impl.h index f9889d5372..da9936dbd9 100644 --- a/src/scalar_8x32_impl.h +++ b/src/scalar_8x32_impl.h @@ -142,8 +142,9 @@ static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag) { uint64_t t; + volatile int vflag = flag; VERIFY_CHECK(bit < 256); - bit += ((uint32_t) flag - 1) & 0x100; /* forcing (bit >> 5) > 7 makes this a noop */ + bit += ((uint32_t) vflag - 1) & 0x100; /* forcing (bit >> 5) > 7 makes this a noop */ t = (uint64_t)r->d[0] + (((uint32_t)((bit >> 5) == 0)) << (bit & 0x1F)); r->d[0] = t & 0xFFFFFFFFULL; t >>= 32; t += (uint64_t)r->d[1] + (((uint32_t)((bit >> 5) == 1)) << (bit & 0x1F)); From 97a98bed1ed479b1a23d8ae788020d8a6e081cf0 Mon Sep 17 00:00:00 2001 From: Tim Ruffing Date: Thu, 11 Aug 2022 16:02:56 +0200 Subject: [PATCH 086/100] schnorrsig: Refactor test vector code to allow varlen messages --- src/modules/schnorrsig/tests_impl.h | 60 ++++++++++++++++------------- 1 file changed, 34 insertions(+), 26 deletions(-) diff --git a/src/modules/schnorrsig/tests_impl.h b/src/modules/schnorrsig/tests_impl.h index 062005ee63..2da5d802aa 100644 --- a/src/modules/schnorrsig/tests_impl.h +++ b/src/modules/schnorrsig/tests_impl.h @@ -215,28 +215,36 @@ static void test_schnorrsig_sha256_tagged(void) { /* Helper function for schnorrsig_bip_vectors * Signs the message and checks that it's the same as expected_sig. */ -static void test_schnorrsig_bip_vectors_check_signing(const unsigned char *sk, const unsigned char *pk_serialized, const unsigned char *aux_rand, const unsigned char *msg32, const unsigned char *expected_sig) { +static void test_schnorrsig_bip_vectors_check_signing(const unsigned char *sk, const unsigned char *pk_serialized, const unsigned char *aux_rand, const unsigned char *msg, size_t msglen, const unsigned char *expected_sig) { unsigned char sig[64]; secp256k1_keypair keypair; secp256k1_xonly_pubkey pk, pk_expected; + secp256k1_schnorrsig_extraparams extraparams = SECP256K1_SCHNORRSIG_EXTRAPARAMS_INIT; + extraparams.ndata = (unsigned char*)aux_rand; + CHECK(secp256k1_keypair_create(CTX, &keypair, sk)); - CHECK(secp256k1_schnorrsig_sign32(CTX, sig, msg32, &keypair, aux_rand)); + CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, msglen, &keypair, &extraparams)); CHECK(secp256k1_memcmp_var(sig, expected_sig, 64) == 0); + if (msglen == 32) { + memset(sig, 0, 64); + CHECK(secp256k1_schnorrsig_sign32(CTX, sig, msg, &keypair, aux_rand)); + CHECK(secp256k1_memcmp_var(sig, expected_sig, 64) == 0); + } CHECK(secp256k1_xonly_pubkey_parse(CTX, &pk_expected, pk_serialized)); CHECK(secp256k1_keypair_xonly_pub(CTX, &pk, NULL, &keypair)); CHECK(secp256k1_memcmp_var(&pk, &pk_expected, sizeof(pk)) == 0); - CHECK(secp256k1_schnorrsig_verify(CTX, sig, msg32, 32, &pk)); + CHECK(secp256k1_schnorrsig_verify(CTX, sig, msg, msglen, &pk)); } /* Helper function for schnorrsig_bip_vectors * Checks that both verify and verify_batch (TODO) return the same value as expected. */ -static void test_schnorrsig_bip_vectors_check_verify(const unsigned char *pk_serialized, const unsigned char *msg32, const unsigned char *sig, int expected) { +static void test_schnorrsig_bip_vectors_check_verify(const unsigned char *pk_serialized, const unsigned char *msg, size_t msglen, const unsigned char *sig, int expected) { secp256k1_xonly_pubkey pk; CHECK(secp256k1_xonly_pubkey_parse(CTX, &pk, pk_serialized)); - CHECK(expected == secp256k1_schnorrsig_verify(CTX, sig, msg32, 32, &pk)); + CHECK(expected == secp256k1_schnorrsig_verify(CTX, sig, msg, msglen, &pk)); } /* Test vectors according to BIP-340 ("Schnorr Signatures for secp256k1"). See @@ -256,7 +264,7 @@ static void test_schnorrsig_bip_vectors(void) { 0xB5, 0x31, 0xC8, 0x45, 0x83, 0x6F, 0x99, 0xB0, 0x86, 0x01, 0xF1, 0x13, 0xBC, 0xE0, 0x36, 0xF9 }; - unsigned char aux_rand[32] = { + const unsigned char aux_rand[32] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -278,8 +286,8 @@ static void test_schnorrsig_bip_vectors(void) { 0xEB, 0xEE, 0xE8, 0xFD, 0xB2, 0x17, 0x2F, 0x47, 0x7D, 0xF4, 0x90, 0x0D, 0x31, 0x05, 0x36, 0xC0 }; - test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sig); - test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 1); + test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sizeof(msg), sig); + test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 1); } { /* Test vector 1 */ @@ -295,7 +303,7 @@ static void test_schnorrsig_bip_vectors(void) { 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59 }; - unsigned char aux_rand[32] = { + const unsigned char aux_rand[32] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -317,8 +325,8 @@ static void test_schnorrsig_bip_vectors(void) { 0x89, 0x7E, 0xFC, 0xB6, 0x39, 0xEA, 0x87, 0x1C, 0xFA, 0x95, 0xF6, 0xDE, 0x33, 0x9E, 0x4B, 0x0A }; - test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sig); - test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 1); + test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sizeof(msg), sig); + test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 1); } { /* Test vector 2 */ @@ -334,7 +342,7 @@ static void test_schnorrsig_bip_vectors(void) { 0x01, 0x39, 0x71, 0x53, 0x09, 0xB0, 0x86, 0xC9, 0x60, 0xE1, 0x8F, 0xD9, 0x69, 0x77, 0x4E, 0xB8 }; - unsigned char aux_rand[32] = { + const unsigned char aux_rand[32] = { 0xC8, 0x7A, 0xA5, 0x38, 0x24, 0xB4, 0xD7, 0xAE, 0x2E, 0xB0, 0x35, 0xA2, 0xB5, 0xBB, 0xBC, 0xCC, 0x08, 0x0E, 0x76, 0xCD, 0xC6, 0xD1, 0x69, 0x2C, @@ -356,8 +364,8 @@ static void test_schnorrsig_bip_vectors(void) { 0x7A, 0xDE, 0xA9, 0x8D, 0x82, 0xF8, 0x48, 0x1E, 0x0E, 0x1E, 0x03, 0x67, 0x4A, 0x6F, 0x3F, 0xB7 }; - test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sig); - test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 1); + test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sizeof(msg), sig); + test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 1); } { /* Test vector 3 */ @@ -373,7 +381,7 @@ static void test_schnorrsig_bip_vectors(void) { 0x3A, 0x0D, 0x95, 0xFB, 0xF2, 0x1D, 0x46, 0x8A, 0x1B, 0x33, 0xF8, 0xC1, 0x60, 0xD8, 0xF5, 0x17 }; - unsigned char aux_rand[32] = { + const unsigned char aux_rand[32] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, @@ -395,8 +403,8 @@ static void test_schnorrsig_bip_vectors(void) { 0xF2, 0x5F, 0xD7, 0x88, 0x81, 0xEB, 0xB3, 0x27, 0x71, 0xFC, 0x59, 0x22, 0xEF, 0xC6, 0x6E, 0xA3 }; - test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sig); - test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 1); + test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sizeof(msg), sig); + test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 1); } { /* Test vector 4 */ @@ -422,7 +430,7 @@ static void test_schnorrsig_bip_vectors(void) { 0x60, 0xCB, 0x71, 0xC0, 0x4E, 0x80, 0xF5, 0x93, 0x06, 0x0B, 0x07, 0xD2, 0x83, 0x08, 0xD7, 0xF4 }; - test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 1); + test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 1); } { /* Test vector 5 */ @@ -460,7 +468,7 @@ static void test_schnorrsig_bip_vectors(void) { 0x7A, 0x73, 0xC6, 0x43, 0xE1, 0x66, 0xBE, 0x5E, 0xBE, 0xAF, 0xA3, 0x4B, 0x1A, 0xC5, 0x53, 0xE2 }; - test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 0); + test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 0); } { /* Test vector 7 */ @@ -486,7 +494,7 @@ static void test_schnorrsig_bip_vectors(void) { 0x62, 0x2A, 0x95, 0x4C, 0xFE, 0x54, 0x57, 0x35, 0xAA, 0xEA, 0x51, 0x34, 0xFC, 0xCD, 0xB2, 0xBD }; - test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 0); + test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 0); } { /* Test vector 8 */ @@ -512,7 +520,7 @@ static void test_schnorrsig_bip_vectors(void) { 0xE8, 0xD7, 0xC9, 0x3E, 0x00, 0xC5, 0xED, 0x0C, 0x18, 0x34, 0xFF, 0x0D, 0x0C, 0x2E, 0x6D, 0xA6 }; - test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 0); + test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 0); } { /* Test vector 9 */ @@ -538,7 +546,7 @@ static void test_schnorrsig_bip_vectors(void) { 0x4F, 0xB7, 0x34, 0x76, 0xF0, 0xD5, 0x94, 0xDC, 0xB6, 0x5C, 0x64, 0x25, 0xBD, 0x18, 0x60, 0x51 }; - test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 0); + test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 0); } { /* Test vector 10 */ @@ -564,7 +572,7 @@ static void test_schnorrsig_bip_vectors(void) { 0xDB, 0xA8, 0x7F, 0x11, 0xAC, 0x67, 0x54, 0xF9, 0x37, 0x80, 0xD5, 0xA1, 0x83, 0x7C, 0xF1, 0x97 }; - test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 0); + test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 0); } { /* Test vector 11 */ @@ -590,7 +598,7 @@ static void test_schnorrsig_bip_vectors(void) { 0xD1, 0xD7, 0x13, 0xA8, 0xAE, 0x82, 0xB3, 0x2F, 0xA7, 0x9D, 0x5F, 0x7F, 0xC4, 0x07, 0xD3, 0x9B }; - test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 0); + test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 0); } { /* Test vector 12 */ @@ -616,7 +624,7 @@ static void test_schnorrsig_bip_vectors(void) { 0xD1, 0xD7, 0x13, 0xA8, 0xAE, 0x82, 0xB3, 0x2F, 0xA7, 0x9D, 0x5F, 0x7F, 0xC4, 0x07, 0xD3, 0x9B }; - test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 0); + test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 0); } { /* Test vector 13 */ @@ -642,7 +650,7 @@ static void test_schnorrsig_bip_vectors(void) { 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41 }; - test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 0); + test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 0); } { /* Test vector 14 */ From 28687b03128fbdd23a3f901297f523dfae2f82e3 Mon Sep 17 00:00:00 2001 From: Tim Ruffing Date: Thu, 11 Aug 2022 16:52:39 +0200 Subject: [PATCH 087/100] schnorrsig: Add BIP340 varlen test vectors --- src/modules/schnorrsig/tests_impl.h | 141 ++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) diff --git a/src/modules/schnorrsig/tests_impl.h b/src/modules/schnorrsig/tests_impl.h index 2da5d802aa..ddcb8a599b 100644 --- a/src/modules/schnorrsig/tests_impl.h +++ b/src/modules/schnorrsig/tests_impl.h @@ -664,6 +664,147 @@ static void test_schnorrsig_bip_vectors(void) { /* No need to check the signature of the test vector as parsing the pubkey already fails */ CHECK(!secp256k1_xonly_pubkey_parse(CTX, &pk_parsed, pk)); } + { + /* Test vector 15 */ + const unsigned char sk[32] = { + 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, + 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, + 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, + 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, + }; + const unsigned char pk[32] = { + 0x77, 0x8C, 0xAA, 0x53, 0xB4, 0x39, 0x3A, 0xC4, + 0x67, 0x77, 0x4D, 0x09, 0x49, 0x7A, 0x87, 0x22, + 0x4B, 0xF9, 0xFA, 0xB6, 0xF6, 0xE6, 0x8B, 0x23, + 0x08, 0x64, 0x97, 0x32, 0x4D, 0x6F, 0xD1, 0x17, + }; + const unsigned char aux_rand[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + /* const unsigned char msg[0] = {}; */ + const unsigned char sig[64] = { + 0x71, 0x53, 0x5D, 0xB1, 0x65, 0xEC, 0xD9, 0xFB, + 0xBC, 0x04, 0x6E, 0x5F, 0xFA, 0xEA, 0x61, 0x18, + 0x6B, 0xB6, 0xAD, 0x43, 0x67, 0x32, 0xFC, 0xCC, + 0x25, 0x29, 0x1A, 0x55, 0x89, 0x54, 0x64, 0xCF, + 0x60, 0x69, 0xCE, 0x26, 0xBF, 0x03, 0x46, 0x62, + 0x28, 0xF1, 0x9A, 0x3A, 0x62, 0xDB, 0x8A, 0x64, + 0x9F, 0x2D, 0x56, 0x0F, 0xAC, 0x65, 0x28, 0x27, + 0xD1, 0xAF, 0x05, 0x74, 0xE4, 0x27, 0xAB, 0x63, + }; + test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, NULL, 0, sig); + test_schnorrsig_bip_vectors_check_verify(pk, NULL, 0, sig, 1); + } + { + /* Test vector 16 */ + const unsigned char sk[32] = { + 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, + 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, + 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, + 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, + }; + const unsigned char pk[32] = { + 0x77, 0x8C, 0xAA, 0x53, 0xB4, 0x39, 0x3A, 0xC4, + 0x67, 0x77, 0x4D, 0x09, 0x49, 0x7A, 0x87, 0x22, + 0x4B, 0xF9, 0xFA, 0xB6, 0xF6, 0xE6, 0x8B, 0x23, + 0x08, 0x64, 0x97, 0x32, 0x4D, 0x6F, 0xD1, 0x17, + }; + const unsigned char aux_rand[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + const unsigned char msg[] = { 0x11 }; + const unsigned char sig[64] = { + 0x08, 0xA2, 0x0A, 0x0A, 0xFE, 0xF6, 0x41, 0x24, + 0x64, 0x92, 0x32, 0xE0, 0x69, 0x3C, 0x58, 0x3A, + 0xB1, 0xB9, 0x93, 0x4A, 0xE6, 0x3B, 0x4C, 0x35, + 0x11, 0xF3, 0xAE, 0x11, 0x34, 0xC6, 0xA3, 0x03, + 0xEA, 0x31, 0x73, 0xBF, 0xEA, 0x66, 0x83, 0xBD, + 0x10, 0x1F, 0xA5, 0xAA, 0x5D, 0xBC, 0x19, 0x96, + 0xFE, 0x7C, 0xAC, 0xFC, 0x5A, 0x57, 0x7D, 0x33, + 0xEC, 0x14, 0x56, 0x4C, 0xEC, 0x2B, 0xAC, 0xBF, + }; + test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sizeof(msg), sig); + test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 1); + } + { + /* Test vector 17 */ + const unsigned char sk[32] = { + 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, + 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, + 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, + 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, + }; + const unsigned char pk[32] = { + 0x77, 0x8C, 0xAA, 0x53, 0xB4, 0x39, 0x3A, 0xC4, + 0x67, 0x77, 0x4D, 0x09, 0x49, 0x7A, 0x87, 0x22, + 0x4B, 0xF9, 0xFA, 0xB6, 0xF6, 0xE6, 0x8B, 0x23, + 0x08, 0x64, 0x97, 0x32, 0x4D, 0x6F, 0xD1, 0x17, + }; + const unsigned char aux_rand[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + const unsigned char msg[] = { + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, + 0x11, + }; + const unsigned char sig[64] = { + 0x51, 0x30, 0xF3, 0x9A, 0x40, 0x59, 0xB4, 0x3B, + 0xC7, 0xCA, 0xC0, 0x9A, 0x19, 0xEC, 0xE5, 0x2B, + 0x5D, 0x86, 0x99, 0xD1, 0xA7, 0x1E, 0x3C, 0x52, + 0xDA, 0x9A, 0xFD, 0xB6, 0xB5, 0x0A, 0xC3, 0x70, + 0xC4, 0xA4, 0x82, 0xB7, 0x7B, 0xF9, 0x60, 0xF8, + 0x68, 0x15, 0x40, 0xE2, 0x5B, 0x67, 0x71, 0xEC, + 0xE1, 0xE5, 0xA3, 0x7F, 0xD8, 0x0E, 0x5A, 0x51, + 0x89, 0x7C, 0x55, 0x66, 0xA9, 0x7E, 0xA5, 0xA5, + }; + test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sizeof(msg), sig); + test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 1); + } + { + /* Test vector 18 */ + const unsigned char sk[32] = { + 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, + 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, + 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, + 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, + }; + const unsigned char pk[32] = { + 0x77, 0x8C, 0xAA, 0x53, 0xB4, 0x39, 0x3A, 0xC4, + 0x67, 0x77, 0x4D, 0x09, 0x49, 0x7A, 0x87, 0x22, + 0x4B, 0xF9, 0xFA, 0xB6, 0xF6, 0xE6, 0x8B, 0x23, + 0x08, 0x64, 0x97, 0x32, 0x4D, 0x6F, 0xD1, 0x17, + }; + const unsigned char aux_rand[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + const unsigned char sig[64] = { + 0x40, 0x3B, 0x12, 0xB0, 0xD8, 0x55, 0x5A, 0x34, + 0x41, 0x75, 0xEA, 0x7E, 0xC7, 0x46, 0x56, 0x63, + 0x03, 0x32, 0x1E, 0x5D, 0xBF, 0xA8, 0xBE, 0x6F, + 0x09, 0x16, 0x35, 0x16, 0x3E, 0xCA, 0x79, 0xA8, + 0x58, 0x5E, 0xD3, 0xE3, 0x17, 0x08, 0x07, 0xE7, + 0xC0, 0x3B, 0x72, 0x0F, 0xC5, 0x4C, 0x7B, 0x23, + 0x89, 0x7F, 0xCB, 0xA0, 0xE9, 0xD0, 0xB4, 0xA0, + 0x68, 0x94, 0xCF, 0xD2, 0x49, 0xF2, 0x23, 0x67, + }; + unsigned char msg[100]; + memset(msg, 0x99, sizeof(msg)); + test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sizeof(msg), sig); + test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 1); + } } /* Nonce function that returns constant 0 */ From cd54ac7c1cca509404b62e626a6291f434af88e8 Mon Sep 17 00:00:00 2001 From: Tim Ruffing Date: Thu, 11 Aug 2022 17:05:23 +0200 Subject: [PATCH 088/100] schnorrsig: Improve docs of schnorrsig_sign_custom --- include/secp256k1_schnorrsig.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/include/secp256k1_schnorrsig.h b/include/secp256k1_schnorrsig.h index cd9845c5f6..1ee665fd19 100644 --- a/include/secp256k1_schnorrsig.h +++ b/include/secp256k1_schnorrsig.h @@ -141,8 +141,12 @@ SECP256K1_API int secp256k1_schnorrsig_sign( * variable length messages and accepts a pointer to an extraparams object that * allows customizing signing by passing additional arguments. * - * Creates the same signatures as schnorrsig_sign if msglen is 32 and the - * extraparams.ndata is the same as aux_rand32. + * Equivalent to secp256k1_schnorrsig_sign32(..., aux_rand32) if msglen is 32 + * and extraparams is initialized as follows: + * ``` + * secp256k1_schnorrsig_extraparams extraparams = SECP256K1_SCHNORRSIG_EXTRAPARAMS_INIT; + * extraparams.ndata = (unsigned char*)aux_rand32; + * ``` * * Returns 1 on success, 0 on failure. * Args: ctx: pointer to a context object (not secp256k1_context_static). From 1907f0f1664e3a966daa58be956af18e48834ffd Mon Sep 17 00:00:00 2001 From: Tim Ruffing Date: Thu, 11 May 2023 19:08:35 +0200 Subject: [PATCH 089/100] build: Make tests work with external default callbacks --- src/tests.c | 5 +++++ src/tests_exhaustive.c | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/src/tests.c b/src/tests.c index da1f0132e4..64db038c1b 100644 --- a/src/tests.c +++ b/src/tests.c @@ -10,7 +10,12 @@ #include +#ifdef USE_EXTERNAL_DEFAULT_CALLBACKS + #pragma message("Ignoring USE_EXTERNAL_CALLBACKS in tests.") + #undef USE_EXTERNAL_DEFAULT_CALLBACKS +#endif #include "secp256k1.c" + #include "../include/secp256k1.h" #include "../include/secp256k1_preallocated.h" #include "testrand_impl.h" diff --git a/src/tests_exhaustive.c b/src/tests_exhaustive.c index ee60fe9f45..5829dad515 100644 --- a/src/tests_exhaustive.c +++ b/src/tests_exhaustive.c @@ -13,7 +13,12 @@ #define EXHAUSTIVE_TEST_ORDER 13 #endif +#ifdef USE_EXTERNAL_DEFAULT_CALLBACKS + #pragma message("Ignoring USE_EXTERNAL_CALLBACKS in exhaustive_tests.") + #undef USE_EXTERNAL_DEFAULT_CALLBACKS +#endif #include "secp256k1.c" + #include "../include/secp256k1.h" #include "assumptions.h" #include "group.h" From 5b32602295ff7ad9e1973f96b8ee8344b82f4af0 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Sun, 5 Feb 2023 17:19:00 -0500 Subject: [PATCH 090/100] Split fe_set_b32 into reducing and normalizing variants --- src/bench_internal.c | 8 +++---- src/ecdsa_impl.h | 3 ++- src/eckey_impl.h | 4 ++-- src/ecmult_gen_compute_table_impl.h | 2 +- src/ecmult_gen_impl.h | 2 +- src/field.h | 19 +++++++++------ src/field_10x26_impl.h | 5 +++- src/field_5x52_impl.h | 6 ++++- src/field_impl.h | 23 +++++++++++++++---- src/modules/extrakeys/main_impl.h | 2 +- src/modules/extrakeys/tests_exhaustive_impl.h | 2 +- src/modules/recovery/main_impl.h | 2 +- src/modules/schnorrsig/main_impl.h | 2 +- src/secp256k1.c | 4 ++-- src/tests.c | 21 +++++++++-------- src/tests_exhaustive.c | 2 +- 16 files changed, 68 insertions(+), 39 deletions(-) diff --git a/src/bench_internal.c b/src/bench_internal.c index c248ab8ebc..f3686dd289 100644 --- a/src/bench_internal.c +++ b/src/bench_internal.c @@ -65,10 +65,10 @@ static void bench_setup(void* arg) { secp256k1_scalar_set_b32(&data->scalar[0], init[0], NULL); secp256k1_scalar_set_b32(&data->scalar[1], init[1], NULL); - secp256k1_fe_set_b32(&data->fe[0], init[0]); - secp256k1_fe_set_b32(&data->fe[1], init[1]); - secp256k1_fe_set_b32(&data->fe[2], init[2]); - secp256k1_fe_set_b32(&data->fe[3], init[3]); + secp256k1_fe_set_b32_limit(&data->fe[0], init[0]); + secp256k1_fe_set_b32_limit(&data->fe[1], init[1]); + secp256k1_fe_set_b32_limit(&data->fe[2], init[2]); + secp256k1_fe_set_b32_limit(&data->fe[3], init[3]); CHECK(secp256k1_ge_set_xo_var(&data->ge[0], &data->fe[0], 0)); CHECK(secp256k1_ge_set_xo_var(&data->ge[1], &data->fe[1], 1)); secp256k1_gej_set_ge(&data->gej[0], &data->ge[0]); diff --git a/src/ecdsa_impl.h b/src/ecdsa_impl.h index 90b4b22b77..48e30851b5 100644 --- a/src/ecdsa_impl.h +++ b/src/ecdsa_impl.h @@ -239,7 +239,8 @@ static int secp256k1_ecdsa_sig_verify(const secp256k1_scalar *sigr, const secp25 } #else secp256k1_scalar_get_b32(c, sigr); - secp256k1_fe_set_b32(&xr, c); + /* we can ignore the fe_set_b32_limit return value, because we know the input is in range */ + (void)secp256k1_fe_set_b32_limit(&xr, c); /** We now have the recomputed R point in pr, and its claimed x coordinate (modulo n) * in xr. Naively, we would extract the x coordinate from pr (requiring a inversion modulo p), diff --git a/src/eckey_impl.h b/src/eckey_impl.h index e0506d3e2b..b2fe36fe93 100644 --- a/src/eckey_impl.h +++ b/src/eckey_impl.h @@ -17,10 +17,10 @@ static int secp256k1_eckey_pubkey_parse(secp256k1_ge *elem, const unsigned char *pub, size_t size) { if (size == 33 && (pub[0] == SECP256K1_TAG_PUBKEY_EVEN || pub[0] == SECP256K1_TAG_PUBKEY_ODD)) { secp256k1_fe x; - return secp256k1_fe_set_b32(&x, pub+1) && secp256k1_ge_set_xo_var(elem, &x, pub[0] == SECP256K1_TAG_PUBKEY_ODD); + return secp256k1_fe_set_b32_limit(&x, pub+1) && secp256k1_ge_set_xo_var(elem, &x, pub[0] == SECP256K1_TAG_PUBKEY_ODD); } else if (size == 65 && (pub[0] == SECP256K1_TAG_PUBKEY_UNCOMPRESSED || pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_EVEN || pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_ODD)) { secp256k1_fe x, y; - if (!secp256k1_fe_set_b32(&x, pub+1) || !secp256k1_fe_set_b32(&y, pub+33)) { + if (!secp256k1_fe_set_b32_limit(&x, pub+1) || !secp256k1_fe_set_b32_limit(&y, pub+33)) { return 0; } secp256k1_ge_set_xy(elem, &x, &y); diff --git a/src/ecmult_gen_compute_table_impl.h b/src/ecmult_gen_compute_table_impl.h index ff6a2992dc..7d672b9950 100644 --- a/src/ecmult_gen_compute_table_impl.h +++ b/src/ecmult_gen_compute_table_impl.h @@ -31,7 +31,7 @@ static void secp256k1_ecmult_gen_compute_table(secp256k1_ge_storage* table, cons secp256k1_fe nums_x; secp256k1_ge nums_ge; int r; - r = secp256k1_fe_set_b32(&nums_x, nums_b32); + r = secp256k1_fe_set_b32_limit(&nums_x, nums_b32); (void)r; VERIFY_CHECK(r); r = secp256k1_ge_set_xo_var(&nums_ge, &nums_x, 0); diff --git a/src/ecmult_gen_impl.h b/src/ecmult_gen_impl.h index 4f5ea9f3c0..deb0323b7a 100644 --- a/src/ecmult_gen_impl.h +++ b/src/ecmult_gen_impl.h @@ -108,7 +108,7 @@ static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const memset(keydata, 0, sizeof(keydata)); /* Accept unobservably small non-uniformity. */ secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32); - overflow = !secp256k1_fe_set_b32(&s, nonce32); + overflow = !secp256k1_fe_set_b32_limit(&s, nonce32); overflow |= secp256k1_fe_is_zero(&s); secp256k1_fe_cmov(&s, &secp256k1_fe_one, overflow); /* Randomize the projection to defend against multiplier sidechannels. diff --git a/src/field.h b/src/field.h index 2c8fbc28e3..bbc836b199 100644 --- a/src/field.h +++ b/src/field.h @@ -85,7 +85,8 @@ static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST( # define secp256k1_fe_is_zero secp256k1_fe_impl_is_zero # define secp256k1_fe_is_odd secp256k1_fe_impl_is_odd # define secp256k1_fe_cmp_var secp256k1_fe_impl_cmp_var -# define secp256k1_fe_set_b32 secp256k1_fe_impl_set_b32 +# define secp256k1_fe_set_b32_mod secp256k1_fe_impl_set_b32_mod +# define secp256k1_fe_set_b32_limit secp256k1_fe_impl_set_b32_limit # define secp256k1_fe_get_b32 secp256k1_fe_impl_get_b32 # define secp256k1_fe_negate secp256k1_fe_impl_negate # define secp256k1_fe_mul_int secp256k1_fe_impl_mul_int @@ -189,16 +190,20 @@ static int secp256k1_fe_equal_var(const secp256k1_fe *a, const secp256k1_fe *b); */ static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b); -/** Set a field element equal to a provided 32-byte big endian value. +/** Set a field element equal to a provided 32-byte big endian value, reducing it. * * On input, r does not need to be initalized. a must be a pointer to an initialized 32-byte array. - * On output, r = a (mod p). It will have magnitude 1, and if (a < p), it will be normalized. - * If not, it will only be weakly normalized. Returns whether (a < p). + * On output, r = a (mod p). It will have magnitude 1, and not be normalized. + */ +static void secp256k1_fe_set_b32_mod(secp256k1_fe *r, const unsigned char *a); + +/** Set a field element equal to a provided 32-byte big endian value, checking for overflow. * - * Note that this function is unusual in that the normalization of the output depends on the - * run-time value of a. + * On input, r does not need to be initalized. a must be a pointer to an initialized 32-byte array. + * On output, r = a if (a < p), it will be normalized with magnitude 1, and 1 is returned. + * If a >= p, 0 is returned, and r will be made invalid (and must not be used without overwriting). */ -static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a); +static int secp256k1_fe_set_b32_limit(secp256k1_fe *r, const unsigned char *a); /** Convert a field element to 32-byte big endian byte array. * On input, a must be a valid normalized field element, and r a pointer to a 32-byte array. diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h index 3f719c161f..c1b32b80a8 100644 --- a/src/field_10x26_impl.h +++ b/src/field_10x26_impl.h @@ -290,7 +290,7 @@ static int secp256k1_fe_impl_cmp_var(const secp256k1_fe *a, const secp256k1_fe * return 0; } -static int secp256k1_fe_impl_set_b32(secp256k1_fe *r, const unsigned char *a) { +static void secp256k1_fe_impl_set_b32_mod(secp256k1_fe *r, const unsigned char *a) { r->n[0] = (uint32_t)a[31] | ((uint32_t)a[30] << 8) | ((uint32_t)a[29] << 16) | ((uint32_t)(a[28] & 0x3) << 24); r->n[1] = (uint32_t)((a[28] >> 2) & 0x3f) | ((uint32_t)a[27] << 6) | ((uint32_t)a[26] << 14) | ((uint32_t)(a[25] & 0xf) << 22); r->n[2] = (uint32_t)((a[25] >> 4) & 0xf) | ((uint32_t)a[24] << 4) | ((uint32_t)a[23] << 12) | ((uint32_t)(a[22] & 0x3f) << 20); @@ -301,7 +301,10 @@ static int secp256k1_fe_impl_set_b32(secp256k1_fe *r, const unsigned char *a) { r->n[7] = (uint32_t)((a[9] >> 6) & 0x3) | ((uint32_t)a[8] << 2) | ((uint32_t)a[7] << 10) | ((uint32_t)a[6] << 18); r->n[8] = (uint32_t)a[5] | ((uint32_t)a[4] << 8) | ((uint32_t)a[3] << 16) | ((uint32_t)(a[2] & 0x3) << 24); r->n[9] = (uint32_t)((a[2] >> 2) & 0x3f) | ((uint32_t)a[1] << 6) | ((uint32_t)a[0] << 14); +} +static int secp256k1_fe_impl_set_b32_limit(secp256k1_fe *r, const unsigned char *a) { + secp256k1_fe_impl_set_b32_mod(r, a); return !((r->n[9] == 0x3FFFFFUL) & ((r->n[8] & r->n[7] & r->n[6] & r->n[5] & r->n[4] & r->n[3] & r->n[2]) == 0x3FFFFFFUL) & ((r->n[1] + 0x40UL + ((r->n[0] + 0x3D1UL) >> 26)) > 0x3FFFFFFUL)); } diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h index a44a64b5a1..0a4cc1a630 100644 --- a/src/field_5x52_impl.h +++ b/src/field_5x52_impl.h @@ -236,7 +236,7 @@ static int secp256k1_fe_impl_cmp_var(const secp256k1_fe *a, const secp256k1_fe * return 0; } -static int secp256k1_fe_impl_set_b32(secp256k1_fe *r, const unsigned char *a) { +static void secp256k1_fe_impl_set_b32_mod(secp256k1_fe *r, const unsigned char *a) { r->n[0] = (uint64_t)a[31] | ((uint64_t)a[30] << 8) | ((uint64_t)a[29] << 16) @@ -271,6 +271,10 @@ static int secp256k1_fe_impl_set_b32(secp256k1_fe *r, const unsigned char *a) { | ((uint64_t)a[2] << 24) | ((uint64_t)a[1] << 32) | ((uint64_t)a[0] << 40); +} + +static int secp256k1_fe_impl_set_b32_limit(secp256k1_fe *r, const unsigned char *a) { + secp256k1_fe_impl_set_b32_mod(r, a); return !((r->n[4] == 0x0FFFFFFFFFFFFULL) & ((r->n[3] & r->n[2] & r->n[1]) == 0xFFFFFFFFFFFFFULL) & (r->n[0] >= 0xFFFFEFFFFFC2FULL)); } diff --git a/src/field_impl.h b/src/field_impl.h index c082d8f553..7270375007 100644 --- a/src/field_impl.h +++ b/src/field_impl.h @@ -260,13 +260,26 @@ SECP256K1_INLINE static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const se return secp256k1_fe_impl_cmp_var(a, b); } -static int secp256k1_fe_impl_set_b32(secp256k1_fe *r, const unsigned char *a); -SECP256K1_INLINE static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a) { - int ret = secp256k1_fe_impl_set_b32(r, a); +static void secp256k1_fe_impl_set_b32_mod(secp256k1_fe *r, const unsigned char *a); +SECP256K1_INLINE static void secp256k1_fe_set_b32_mod(secp256k1_fe *r, const unsigned char *a) { + secp256k1_fe_impl_set_b32_mod(r, a); r->magnitude = 1; - r->normalized = ret; + r->normalized = 0; secp256k1_fe_verify(r); - return ret; +} + +static int secp256k1_fe_impl_set_b32_limit(secp256k1_fe *r, const unsigned char *a); +SECP256K1_INLINE static int secp256k1_fe_set_b32_limit(secp256k1_fe *r, const unsigned char *a) { + if (secp256k1_fe_impl_set_b32_limit(r, a)) { + r->magnitude = 1; + r->normalized = 1; + secp256k1_fe_verify(r); + return 1; + } else { + /* Mark the output field element as invalid. */ + r->magnitude = -1; + return 0; + } } static void secp256k1_fe_impl_get_b32(unsigned char *r, const secp256k1_fe *a); diff --git a/src/modules/extrakeys/main_impl.h b/src/modules/extrakeys/main_impl.h index 7352004457..0c7e266777 100644 --- a/src/modules/extrakeys/main_impl.h +++ b/src/modules/extrakeys/main_impl.h @@ -28,7 +28,7 @@ int secp256k1_xonly_pubkey_parse(const secp256k1_context* ctx, secp256k1_xonly_p memset(pubkey, 0, sizeof(*pubkey)); ARG_CHECK(input32 != NULL); - if (!secp256k1_fe_set_b32(&x, input32)) { + if (!secp256k1_fe_set_b32_limit(&x, input32)) { return 0; } if (!secp256k1_ge_set_xo_var(&pk, &x, 0)) { diff --git a/src/modules/extrakeys/tests_exhaustive_impl.h b/src/modules/extrakeys/tests_exhaustive_impl.h index 5ecc90d50f..d3d817a131 100644 --- a/src/modules/extrakeys/tests_exhaustive_impl.h +++ b/src/modules/extrakeys/tests_exhaustive_impl.h @@ -47,7 +47,7 @@ static void test_exhaustive_extrakeys(const secp256k1_context *ctx, const secp25 CHECK(secp256k1_memcmp_var(xonly_pubkey_bytes[i - 1], buf, 32) == 0); /* Compare the xonly_pubkey bytes against the precomputed group. */ - secp256k1_fe_set_b32(&fe, xonly_pubkey_bytes[i - 1]); + secp256k1_fe_set_b32_mod(&fe, xonly_pubkey_bytes[i - 1]); CHECK(secp256k1_fe_equal_var(&fe, &group[i].x)); /* Check the parity against the precomputed group. */ diff --git a/src/modules/recovery/main_impl.h b/src/modules/recovery/main_impl.h index e7906eb62e..76a005e017 100644 --- a/src/modules/recovery/main_impl.h +++ b/src/modules/recovery/main_impl.h @@ -98,7 +98,7 @@ static int secp256k1_ecdsa_sig_recover(const secp256k1_scalar *sigr, const secp2 } secp256k1_scalar_get_b32(brx, sigr); - r = secp256k1_fe_set_b32(&fx, brx); + r = secp256k1_fe_set_b32_limit(&fx, brx); (void)r; VERIFY_CHECK(r); /* brx comes from a scalar, so is less than the order; certainly less than p */ if (recid & 2) { diff --git a/src/modules/schnorrsig/main_impl.h b/src/modules/schnorrsig/main_impl.h index cd651591c4..4e7b45a045 100644 --- a/src/modules/schnorrsig/main_impl.h +++ b/src/modules/schnorrsig/main_impl.h @@ -232,7 +232,7 @@ int secp256k1_schnorrsig_verify(const secp256k1_context* ctx, const unsigned cha ARG_CHECK(msg != NULL || msglen == 0); ARG_CHECK(pubkey != NULL); - if (!secp256k1_fe_set_b32(&rx, &sig64[0])) { + if (!secp256k1_fe_set_b32_limit(&rx, &sig64[0])) { return 0; } diff --git a/src/secp256k1.c b/src/secp256k1.c index 086cbc85cd..41b8285736 100644 --- a/src/secp256k1.c +++ b/src/secp256k1.c @@ -247,8 +247,8 @@ static int secp256k1_pubkey_load(const secp256k1_context* ctx, secp256k1_ge* ge, } else { /* Otherwise, fall back to 32-byte big endian for X and Y. */ secp256k1_fe x, y; - secp256k1_fe_set_b32(&x, pubkey->data); - secp256k1_fe_set_b32(&y, pubkey->data + 32); + secp256k1_fe_set_b32_mod(&x, pubkey->data); + secp256k1_fe_set_b32_mod(&y, pubkey->data + 32); secp256k1_ge_set_xy(ge, &x, &y); } ARG_CHECK(!secp256k1_fe_is_zero(&ge->x)); diff --git a/src/tests.c b/src/tests.c index 64db038c1b..70cee3176b 100644 --- a/src/tests.c +++ b/src/tests.c @@ -90,7 +90,7 @@ static void random_field_element_test(secp256k1_fe *fe) { do { unsigned char b32[32]; secp256k1_testrand256_test(b32); - if (secp256k1_fe_set_b32(fe, b32)) { + if (secp256k1_fe_set_b32_limit(fe, b32)) { break; } } while(1); @@ -2957,7 +2957,7 @@ static void random_fe(secp256k1_fe *x) { unsigned char bin[32]; do { secp256k1_testrand256(bin); - if (secp256k1_fe_set_b32(x, bin)) { + if (secp256k1_fe_set_b32_limit(x, bin)) { return; } } while(1); @@ -2967,7 +2967,7 @@ static void random_fe_test(secp256k1_fe *x) { unsigned char bin[32]; do { secp256k1_testrand256_test(bin); - if (secp256k1_fe_set_b32(x, bin)) { + if (secp256k1_fe_set_b32_limit(x, bin)) { return; } } while(1); @@ -3021,7 +3021,7 @@ static void run_field_convert(void) { unsigned char b322[32]; secp256k1_fe_storage fes2; /* Check conversions to fe. */ - CHECK(secp256k1_fe_set_b32(&fe2, b32)); + CHECK(secp256k1_fe_set_b32_limit(&fe2, b32)); CHECK(secp256k1_fe_equal_var(&fe, &fe2)); secp256k1_fe_from_storage(&fe2, &fes); CHECK(secp256k1_fe_equal_var(&fe, &fe2)); @@ -3043,7 +3043,8 @@ static void run_field_be32_overflow(void) { static const unsigned char zero[32] = { 0x00 }; unsigned char out[32]; secp256k1_fe fe; - CHECK(secp256k1_fe_set_b32(&fe, zero_overflow) == 0); + CHECK(secp256k1_fe_set_b32_limit(&fe, zero_overflow) == 0); + secp256k1_fe_set_b32_mod(&fe, zero_overflow); CHECK(secp256k1_fe_normalizes_to_zero(&fe) == 1); secp256k1_fe_normalize(&fe); CHECK(secp256k1_fe_is_zero(&fe) == 1); @@ -3065,7 +3066,8 @@ static void run_field_be32_overflow(void) { }; unsigned char out[32]; secp256k1_fe fe; - CHECK(secp256k1_fe_set_b32(&fe, one_overflow) == 0); + CHECK(secp256k1_fe_set_b32_limit(&fe, one_overflow) == 0); + secp256k1_fe_set_b32_mod(&fe, one_overflow); secp256k1_fe_normalize(&fe); CHECK(secp256k1_fe_cmp_var(&fe, &secp256k1_fe_one) == 0); secp256k1_fe_get_b32(out, &fe); @@ -3087,7 +3089,8 @@ static void run_field_be32_overflow(void) { unsigned char out[32]; secp256k1_fe fe; const secp256k1_fe fe_ff = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0x01, 0x000003d0); - CHECK(secp256k1_fe_set_b32(&fe, ff_overflow) == 0); + CHECK(secp256k1_fe_set_b32_limit(&fe, ff_overflow) == 0); + secp256k1_fe_set_b32_mod(&fe, ff_overflow); secp256k1_fe_normalize(&fe); CHECK(secp256k1_fe_cmp_var(&fe, &fe_ff) == 0); secp256k1_fe_get_b32(out, &fe); @@ -3673,7 +3676,7 @@ static void run_inverse_tests(void) b32[31] = i & 0xff; b32[30] = (i >> 8) & 0xff; secp256k1_scalar_set_b32(&x_scalar, b32, NULL); - secp256k1_fe_set_b32(&x_fe, b32); + secp256k1_fe_set_b32_mod(&x_fe, b32); for (var = 0; var <= 1; ++var) { test_inverse_scalar(NULL, &x_scalar, var); test_inverse_field(NULL, &x_fe, var); @@ -3690,7 +3693,7 @@ static void run_inverse_tests(void) for (i = 0; i < 64 * COUNT; ++i) { (testrand ? secp256k1_testrand256_test : secp256k1_testrand256)(b32); secp256k1_scalar_set_b32(&x_scalar, b32, NULL); - secp256k1_fe_set_b32(&x_fe, b32); + secp256k1_fe_set_b32_mod(&x_fe, b32); for (var = 0; var <= 1; ++var) { test_inverse_scalar(NULL, &x_scalar, var); test_inverse_field(NULL, &x_fe, var); diff --git a/src/tests_exhaustive.c b/src/tests_exhaustive.c index 5829dad515..d35acdd58e 100644 --- a/src/tests_exhaustive.c +++ b/src/tests_exhaustive.c @@ -60,7 +60,7 @@ static void random_fe(secp256k1_fe *x) { unsigned char bin[32]; do { secp256k1_testrand256(bin); - if (secp256k1_fe_set_b32(x, bin)) { + if (secp256k1_fe_set_b32_limit(x, bin)) { return; } } while(1); From 0c729ba70d963f2798184b0b8524d7de2f3ced9f Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 12 May 2023 05:15:05 -0400 Subject: [PATCH 091/100] Bugfix: mark outputs as early clobber in scalar x86_64 asm In the existing code, the compiler is allowed to allocate the RSI register for outputs m0, m1, or m2, which are written to before the input in RSI is read from. Fix this by marking them as early clobber. Reported by ehoffman2 in https://github.com/bitcoin-core/secp256k1/issues/766 --- src/scalar_4x64_impl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scalar_4x64_impl.h b/src/scalar_4x64_impl.h index e50ec3ae94..0d342fd847 100644 --- a/src/scalar_4x64_impl.h +++ b/src/scalar_4x64_impl.h @@ -383,7 +383,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l) "movq %%r10, %q5\n" /* extract m6 */ "movq %%r8, %q6\n" - : "=g"(m0), "=g"(m1), "=g"(m2), "=g"(m3), "=g"(m4), "=g"(m5), "=g"(m6) + : "=&g"(m0), "=&g"(m1), "=&g"(m2), "=g"(m3), "=g"(m4), "=g"(m5), "=g"(m6) : "S"(l), "i"(SECP256K1_N_C_0), "i"(SECP256K1_N_C_1) : "rax", "rdx", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "cc"); From 350b4bd6e6efd3c62875820fdeb2740738937922 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 12 May 2023 05:17:11 -0400 Subject: [PATCH 092/100] Mark stack variables as early clobber for technical correctness In the field 5x52 asm for x86_64, stack variables are provided as outputs. The existing inputs are all forcibly allocated to registers, so cannot coincide, but mark them as early clobber anyway to make this clearer. --- src/field_5x52_asm_impl.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/field_5x52_asm_impl.h b/src/field_5x52_asm_impl.h index e8efa61085..04a9af2105 100644 --- a/src/field_5x52_asm_impl.h +++ b/src/field_5x52_asm_impl.h @@ -280,7 +280,7 @@ __asm__ __volatile__( "addq %%rsi,%%r8\n" /* r[4] = c */ "movq %%r8,32(%%rdi)\n" -: "+S"(a), "=m"(tmp1), "=m"(tmp2), "=m"(tmp3) +: "+S"(a), "=&m"(tmp1), "=&m"(tmp2), "=&m"(tmp3) : "b"(b), "D"(r) : "%rax", "%rcx", "%rdx", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", "cc", "memory" ); @@ -495,7 +495,7 @@ __asm__ __volatile__( "addq %%rsi,%%r8\n" /* r[4] = c */ "movq %%r8,32(%%rdi)\n" -: "+S"(a), "=m"(tmp1), "=m"(tmp2), "=m"(tmp3) +: "+S"(a), "=&m"(tmp1), "=&m"(tmp2), "=&m"(tmp3) : "D"(r) : "%rax", "%rbx", "%rcx", "%rdx", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", "cc", "memory" ); From ed4ba238e2cb2f24301c1add238cf7ff062286c3 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Fri, 12 May 2023 10:38:50 +0100 Subject: [PATCH 093/100] cmake: Add `check_arm32_assembly` function --- CMakeLists.txt | 8 +++++++- cmake/CheckArm32Assembly.cmake | 6 ++++++ cmake/source_arm32.s | 9 +++++++++ 3 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 cmake/CheckArm32Assembly.cmake create mode 100644 cmake/source_arm32.s diff --git a/CMakeLists.txt b/CMakeLists.txt index a1d9eb36e3..c764e6423e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -107,7 +107,13 @@ set_property(CACHE SECP256K1_ASM PROPERTY STRINGS "AUTO" "OFF" "x86_64" "arm32") check_string_option_value(SECP256K1_ASM) if(SECP256K1_ASM STREQUAL "arm32") enable_language(ASM) - add_compile_definitions(USE_EXTERNAL_ASM=1) + include(CheckArm32Assembly) + check_arm32_assembly() + if(HAVE_ARM32_ASM) + add_compile_definitions(USE_EXTERNAL_ASM=1) + else() + message(FATAL_ERROR "ARM32 assembly optimization requested but not available.") + endif() elseif(SECP256K1_ASM) include(Check64bitAssembly) check_64bit_assembly() diff --git a/cmake/CheckArm32Assembly.cmake b/cmake/CheckArm32Assembly.cmake new file mode 100644 index 0000000000..15c44b24b0 --- /dev/null +++ b/cmake/CheckArm32Assembly.cmake @@ -0,0 +1,6 @@ +function(check_arm32_assembly) + try_compile(HAVE_ARM32_ASM + ${CMAKE_BINARY_DIR}/check_arm32_assembly + SOURCES ${CMAKE_SOURCE_DIR}/cmake/source_arm32.s + ) +endfunction() diff --git a/cmake/source_arm32.s b/cmake/source_arm32.s new file mode 100644 index 0000000000..d3d9347057 --- /dev/null +++ b/cmake/source_arm32.s @@ -0,0 +1,9 @@ +.syntax unified +.eabi_attribute 24, 1 +.eabi_attribute 25, 1 +.text +.global main +main: + ldr r0, =0x002A + mov r7, #1 + swi 0 From 03246457a8f7091e13af13a50d7ae33cf42e08b5 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Thu, 11 May 2023 19:21:51 +0100 Subject: [PATCH 094/100] autotools: Add `SECP_ARM32_ASM_CHECK` macro --- build-aux/m4/bitcoin_secp.m4 | 19 +++++++++++++++++++ configure.ac | 4 ++++ 2 files changed, 23 insertions(+) diff --git a/build-aux/m4/bitcoin_secp.m4 b/build-aux/m4/bitcoin_secp.m4 index 154157ffb4..6d46b9e854 100644 --- a/build-aux/m4/bitcoin_secp.m4 +++ b/build-aux/m4/bitcoin_secp.m4 @@ -9,6 +9,25 @@ AC_LINK_IFELSE([AC_LANG_PROGRAM([[ AC_MSG_RESULT([$has_64bit_asm]) ]) +AC_DEFUN([SECP_ARM32_ASM_CHECK], [ + AC_MSG_CHECKING(for ARM32 assembly availability) + SECP_ARM32_ASM_CHECK_CFLAGS_saved_CFLAGS="$CFLAGS" + CFLAGS="-x assembler" + AC_LINK_IFELSE([AC_LANG_SOURCE([[ + .syntax unified + .eabi_attribute 24, 1 + .eabi_attribute 25, 1 + .text + .global main + main: + ldr r0, =0x002A + mov r7, #1 + swi 0 + ]])], [has_arm32_asm=yes], [has_arm32_asm=no]) + AC_MSG_RESULT([$has_arm32_asm]) + CFLAGS="$SECP_ARM32_ASM_CHECK_CFLAGS_saved_CFLAGS" +]) + AC_DEFUN([SECP_VALGRIND_CHECK],[ AC_MSG_CHECKING([for valgrind support]) if test x"$has_valgrind" != x"yes"; then diff --git a/configure.ac b/configure.ac index 0b99aa3a98..c898b9239a 100644 --- a/configure.ac +++ b/configure.ac @@ -280,6 +280,10 @@ else fi ;; arm32) + SECP_ARM32_ASM_CHECK + if test x"$has_arm32_asm" != x"yes"; then + AC_MSG_ERROR([ARM32 assembly optimization requested but not available]) + fi ;; no) ;; From 8c9ae37a5a26cdeb6365624fee43f41b238830e4 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 12 May 2023 05:47:59 -0400 Subject: [PATCH 095/100] Add release note --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d23662a93..f1ebb6f2c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +#### Fixed + - Fixed an old bug that permitted compilers to potentially output bad assembly code on x86_64. In theory, it could lead to a crash or a read of unrelated memory, but this has never been observed on any compilers so far. + ## [0.3.1] - 2023-04-10 We strongly recommend updating to 0.3.1 if you use or plan to use Clang >=14 to compile libsecp256k1, e.g., Xcode >=14 on macOS has Clang >=14. When in doubt, check the Clang version using `clang -v`. From c6bb29b3037c6b5264f2d2916c5a2d38de25df19 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Fri, 12 May 2023 10:50:18 +0100 Subject: [PATCH 096/100] build: Rename `64bit` to `x86_64` --- CMakeLists.txt | 6 +++--- build-aux/m4/bitcoin_secp.m4 | 6 +++--- ...Check64bitAssembly.cmake => CheckX86_64Assembly.cmake} | 6 +++--- configure.ac | 8 ++++---- 4 files changed, 13 insertions(+), 13 deletions(-) rename cmake/{Check64bitAssembly.cmake => CheckX86_64Assembly.cmake} (70%) diff --git a/CMakeLists.txt b/CMakeLists.txt index c764e6423e..f1dac7b248 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -115,9 +115,9 @@ if(SECP256K1_ASM STREQUAL "arm32") message(FATAL_ERROR "ARM32 assembly optimization requested but not available.") endif() elseif(SECP256K1_ASM) - include(Check64bitAssembly) - check_64bit_assembly() - if(HAS_64BIT_ASM) + include(CheckX86_64Assembly) + check_x86_64_assembly() + if(HAVE_X86_64_ASM) set(SECP256K1_ASM "x86_64") add_compile_definitions(USE_ASM_X86_64=1) elseif(SECP256K1_ASM STREQUAL "AUTO") diff --git a/build-aux/m4/bitcoin_secp.m4 b/build-aux/m4/bitcoin_secp.m4 index 6d46b9e854..11adef4f22 100644 --- a/build-aux/m4/bitcoin_secp.m4 +++ b/build-aux/m4/bitcoin_secp.m4 @@ -1,12 +1,12 @@ dnl escape "$0x" below using the m4 quadrigaph @S|@, and escape it again with a \ for the shell. -AC_DEFUN([SECP_64BIT_ASM_CHECK],[ +AC_DEFUN([SECP_X86_64_ASM_CHECK],[ AC_MSG_CHECKING(for x86_64 assembly availability) AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #include ]],[[ uint64_t a = 11, tmp; __asm__ __volatile__("movq \@S|@0x100000000,%1; mulq %%rsi" : "+a"(a) : "S"(tmp) : "cc", "%rdx"); - ]])],[has_64bit_asm=yes],[has_64bit_asm=no]) -AC_MSG_RESULT([$has_64bit_asm]) + ]])], [has_x86_64_asm=yes], [has_x86_64_asm=no]) +AC_MSG_RESULT([$has_x86_64_asm]) ]) AC_DEFUN([SECP_ARM32_ASM_CHECK], [ diff --git a/cmake/Check64bitAssembly.cmake b/cmake/CheckX86_64Assembly.cmake similarity index 70% rename from cmake/Check64bitAssembly.cmake rename to cmake/CheckX86_64Assembly.cmake index 3f65887765..ae82cd476e 100644 --- a/cmake/Check64bitAssembly.cmake +++ b/cmake/CheckX86_64Assembly.cmake @@ -1,6 +1,6 @@ include(CheckCSourceCompiles) -function(check_64bit_assembly) +function(check_x86_64_assembly) check_c_source_compiles(" #include @@ -9,6 +9,6 @@ function(check_64bit_assembly) uint64_t a = 11, tmp; __asm__ __volatile__(\"movq $0x100000000,%1; mulq %%rsi\" : \"+a\"(a) : \"S\"(tmp) : \"cc\", \"%rdx\"); } - " HAS_64BIT_ASM) - set(HAS_64BIT_ASM ${HAS_64BIT_ASM} PARENT_SCOPE) + " HAVE_X86_64_ASM) + set(HAVE_X86_64_ASM ${HAVE_X86_64_ASM} PARENT_SCOPE) endfunction() diff --git a/configure.ac b/configure.ac index c898b9239a..3db87be164 100644 --- a/configure.ac +++ b/configure.ac @@ -263,8 +263,8 @@ else fi if test x"$req_asm" = x"auto"; then - SECP_64BIT_ASM_CHECK - if test x"$has_64bit_asm" = x"yes"; then + SECP_X86_64_ASM_CHECK + if test x"$has_x86_64_asm" = x"yes"; then set_asm=x86_64 fi if test x"$set_asm" = x; then @@ -274,8 +274,8 @@ else set_asm=$req_asm case $set_asm in x86_64) - SECP_64BIT_ASM_CHECK - if test x"$has_64bit_asm" != x"yes"; then + SECP_X86_64_ASM_CHECK + if test x"$has_x86_64_asm" != x"yes"; then AC_MSG_ERROR([x86_64 assembly optimization requested but not available]) fi ;; From 76b43f3443a9f87ff924f3d96fa14ec02576126d Mon Sep 17 00:00:00 2001 From: Tim Ruffing Date: Fri, 12 May 2023 16:04:16 +0200 Subject: [PATCH 097/100] changelog: Add entry for #1303 --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f1ebb6f2c0..aa1371f10f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +#### Security + - Module `ecdh`: Fix "constant-timeness" issue with GCC 13.1 (and potentially future versions of GCC) that could leave applications using libsecp256k1's ECDH module vulnerable to a timing side-channel attack. The fix avoids secret-dependent control flow during ECDH computations when libsecp256k1 is compiled with GCC 13.1. + #### Fixed - Fixed an old bug that permitted compilers to potentially output bad assembly code on x86_64. In theory, it could lead to a crash or a read of unrelated memory, but this has never been observed on any compilers so far. From 3ad1027a4034da674aeee2a92dfba69b347bbe91 Mon Sep 17 00:00:00 2001 From: Jonas Nick Date: Fri, 12 May 2023 15:05:57 +0000 Subject: [PATCH 098/100] Revert "Remove unused scratch space from API" This reverts commit 712e7f8722eba5dec2bc6b37d75aadeb6f6e633b. --- include/secp256k1.h | 36 ++++++++++++++++++++++++++++++++++++ src/scratch.h | 2 -- src/secp256k1.c | 4 ++-- 3 files changed, 38 insertions(+), 4 deletions(-) diff --git a/include/secp256k1.h b/include/secp256k1.h index d5450e2998..a7a2be7a3a 100644 --- a/include/secp256k1.h +++ b/include/secp256k1.h @@ -49,6 +49,19 @@ 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 @@ -372,6 +385,29 @@ 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: an existing 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: a secp256k1 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 6164330b39..9dcb7581f6 100644 --- a/src/scratch.h +++ b/src/scratch.h @@ -21,8 +21,6 @@ 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 41b8285736..bdbd97cc40 100644 --- a/src/secp256k1.c +++ b/src/secp256k1.c @@ -219,12 +219,12 @@ void secp256k1_context_set_error_callback(secp256k1_context* ctx, void (*fun)(co ctx->error_callback.data = data; } -static secp256k1_scratch_space* secp256k1_scratch_space_create(const secp256k1_context* ctx, size_t max_size) { +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); } -static void secp256k1_scratch_space_destroy(const secp256k1_context *ctx, secp256k1_scratch_space* scratch) { +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 697e1ccf4af7672d45d5ce61cd7d07764a1c8b90 Mon Sep 17 00:00:00 2001 From: Tim Ruffing Date: Fri, 12 May 2023 16:04:30 +0200 Subject: [PATCH 099/100] changelog: Catch up --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index aa1371f10f..265fb88492 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 #### Fixed - Fixed an old bug that permitted compilers to potentially output bad assembly code on x86_64. In theory, it could lead to a crash or a read of unrelated memory, but this has never been observed on any compilers so far. +#### Changed + - Various improvements and changes to CMake builds. CMake builds remain experimental. + - Made API versioning consistent with GNU Autotools builds. + - Switched to `BUILD_SHARED_LIBS` variable for controlling whether to build a static or a shared library. + - Added `SECP256K1_INSTALL` variable for the controlling whether to install the build artefacts. + - Renamed asm build option `arm` to `arm32`. Use `--with-asm=arm32` instead of `--with-asm=arm` (GNU Autotools), and `-DSECP256K1_ASM=arm32` instead of `-DSECP256K1_ASM=arm` (CMake). + ## [0.3.1] - 2023-04-10 We strongly recommend updating to 0.3.1 if you use or plan to use Clang >=14 to compile libsecp256k1, e.g., Xcode >=14 on macOS has Clang >=14. When in doubt, check the Clang version using `clang -v`. From d490ca2046be118258c6a0617c3461c913d1f208 Mon Sep 17 00:00:00 2001 From: Tim Ruffing Date: Fri, 12 May 2023 17:27:36 +0200 Subject: [PATCH 100/100] release: Prepare for 0.3.2 --- CHANGELOG.md | 9 +++++++-- configure.ac | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 265fb88492..6c5dbb843a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,8 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [Unreleased] +## [0.3.2] - 2023-05-13 +We strongly recommend updating to 0.3.2 if you use or plan to use GCC >=13 to compile libsecp256k1. When in doubt, check the GCC version using `gcc -v`. #### Security - Module `ecdh`: Fix "constant-timeness" issue with GCC 13.1 (and potentially future versions of GCC) that could leave applications using libsecp256k1's ECDH module vulnerable to a timing side-channel attack. The fix avoids secret-dependent control flow during ECDH computations when libsecp256k1 is compiled with GCC 13.1. @@ -20,6 +21,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added `SECP256K1_INSTALL` variable for the controlling whether to install the build artefacts. - Renamed asm build option `arm` to `arm32`. Use `--with-asm=arm32` instead of `--with-asm=arm` (GNU Autotools), and `-DSECP256K1_ASM=arm32` instead of `-DSECP256K1_ASM=arm` (CMake). +#### ABI Compatibility +The ABI is compatible with versions 0.3.0 and 0.3.1. + ## [0.3.1] - 2023-04-10 We strongly recommend updating to 0.3.1 if you use or plan to use Clang >=14 to compile libsecp256k1, e.g., Xcode >=14 on macOS has Clang >=14. When in doubt, check the Clang version using `clang -v`. @@ -81,7 +85,8 @@ This version was in fact never released. The number was given by the build system since the introduction of autotools in Jan 2014 (ea0fe5a5bf0c04f9cc955b2966b614f5f378c6f6). Therefore, this version number does not uniquely identify a set of source files. -[unreleased]: https://github.com/bitcoin-core/secp256k1/compare/v0.3.1...HEAD +[unreleased]: https://github.com/bitcoin-core/secp256k1/compare/v0.3.2...HEAD +[0.3.2]: https://github.com/bitcoin-core/secp256k1/compare/v0.3.1...v0.3.2 [0.3.1]: https://github.com/bitcoin-core/secp256k1/compare/v0.3.0...v0.3.1 [0.3.0]: https://github.com/bitcoin-core/secp256k1/compare/v0.2.0...v0.3.0 [0.2.0]: https://github.com/bitcoin-core/secp256k1/compare/423b6d19d373f1224fd671a982584d7e7900bc93..v0.2.0 diff --git a/configure.ac b/configure.ac index 3db87be164..e55be15030 100644 --- a/configure.ac +++ b/configure.ac @@ -6,7 +6,7 @@ AC_PREREQ([2.60]) define(_PKG_VERSION_MAJOR, 0) define(_PKG_VERSION_MINOR, 3) define(_PKG_VERSION_PATCH, 2) -define(_PKG_VERSION_IS_RELEASE, false) +define(_PKG_VERSION_IS_RELEASE, true) # The library version is based on libtool versioning of the ABI. The set of # rules for updating the version can be found here: