From d93f62e3693d6763891edcad11472f9d475177e5 Mon Sep 17 00:00:00 2001 From: Tim Ruffing Date: Wed, 1 Feb 2023 11:37:39 +0100 Subject: [PATCH 001/102] 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 5e6c63cf..2c10814f 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 985c486a..d92def5c 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/102] 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 2c10814f..9fd8de80 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 d92def5c..4262542f 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/102] 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 a52b1fa1..c4bd67b7 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/102] 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 325f35eb..75ffe405 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 a2118044..e8efa610 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 18567b95..b2a391de 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 82ce3f8d..7ec069a8 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 996e542c..7f02e159 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 2eb337cb..3073f314 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 e1003052..73520044 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 1b83575b..0809698b 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 c433adce..92f42879 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 e7800833..5ce1c2d2 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 d109bb9f..721099d0 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 e9b9d7de..1b7481a5 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 86b9334c..ad17d8d3 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 e75c5ad5..f980f47b 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/102] 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 26272d09..43996cc1 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/102] 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 98fb798d..27d694a7 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 417f3285..9e065d55 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 f23e0ec8..f2b6f482 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 5408c9de..82b082a9 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 729b7f85..a9201b74 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 63b6ef03..e7bd6c72 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/102] 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 70a35f09..79dc36ec 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 656c6ea8d8ec5b4f1fa91bc7f0a0ecd10c5cf5a0 Mon Sep 17 00:00:00 2001 From: Jonas Nick Date: Mon, 10 Apr 2023 15:48:42 +0000 Subject: [PATCH 008/102] release cleanup: bump version after 0.3.1 --- CHANGELOG.md | 4 +++- CMakeLists.txt | 4 ++-- configure.ac | 6 +++--- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dab66557..6d23662a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +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.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`. @@ -66,7 +68,7 @@ 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.0...HEAD +[unreleased]: https://github.com/bitcoin-core/secp256k1/compare/v0.3.1...HEAD [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/CMakeLists.txt b/CMakeLists.txt index 5d030d75..a70165e3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,7 +10,7 @@ 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.1 LANGUAGES C) +project(libsecp256k1 VERSION 0.3.2 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: @@ -18,7 +18,7 @@ project(libsecp256k1 VERSION 0.3.1 LANGUAGES C) # All changes in experimental modules are treated as if they don't affect the # interface and therefore only increase the revision. set(${PROJECT_NAME}_LIB_VERSION_CURRENT 2) -set(${PROJECT_NAME}_LIB_VERSION_REVISION 1) +set(${PROJECT_NAME}_LIB_VERSION_REVISION 2) set(${PROJECT_NAME}_LIB_VERSION_AGE 0) set(CMAKE_C_STANDARD 90) diff --git a/configure.ac b/configure.ac index a062b3d0..0b555eac 100644 --- a/configure.ac +++ b/configure.ac @@ -5,8 +5,8 @@ AC_PREREQ([2.60]) # backwards-compatible and therefore at most increase the minor version. define(_PKG_VERSION_MAJOR, 0) define(_PKG_VERSION_MINOR, 3) -define(_PKG_VERSION_PATCH, 1) -define(_PKG_VERSION_IS_RELEASE, true) +define(_PKG_VERSION_PATCH, 2) +define(_PKG_VERSION_IS_RELEASE, false) # The library version is based on libtool versioning of the ABI. The set of # rules for updating the version can be found here: @@ -14,7 +14,7 @@ define(_PKG_VERSION_IS_RELEASE, true) # All changes in experimental modules are treated as if they don't affect the # interface and therefore only increase the revision. define(_LIB_VERSION_CURRENT, 2) -define(_LIB_VERSION_REVISION, 1) +define(_LIB_VERSION_REVISION, 2) define(_LIB_VERSION_AGE, 0) AC_INIT([libsecp256k1],m4_join([.], _PKG_VERSION_MAJOR, _PKG_VERSION_MINOR, _PKG_VERSION_PATCH)m4_if(_PKG_VERSION_IS_RELEASE, [true], [], [-dev]),[https://github.com/bitcoin-core/secp256k1/issues],[libsecp256k1],[https://github.com/bitcoin-core/secp256k1]) 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 009/102] 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 624f5e95..154157ff 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 010/102] 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 0b555eac..6bf5b573 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 0884b645..f60cde43 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 a52b1fa1..507cd559 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 06c67dea9f6d46d3e24e810900fbb03045eae641 Mon Sep 17 00:00:00 2001 From: Tim Ruffing Date: Fri, 14 Apr 2023 07:09:46 +0200 Subject: [PATCH 011/102] autotools: Don't regenerate Wycheproof header automatically Pregenerated files that we distribute should not have dependencies in Makefile.am. For rationale, see the comments about the precomputed table files. See also https://github.com/bitcoin/bitcoin/pull/27445#issuecomment-1502994264 . --- Makefile.am | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile.am b/Makefile.am index 9af8eff9..36e26e3e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -255,8 +255,8 @@ EXTRA_DIST += tools/tests_wycheproof_generate.py TESTVECTORS = src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.h -src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.h: src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.json - python3 tools/tests_wycheproof_generate.py $< > $@ +src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.h: + python3 tools/tests_wycheproof_generate.py src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.json > $@ testvectors: $(TESTVECTORS) From 529b54d9224e680197e6052b505d2a66398e0d36 Mon Sep 17 00:00:00 2001 From: Tim Ruffing Date: Fri, 14 Apr 2023 07:11:46 +0200 Subject: [PATCH 012/102] 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 36e26e3e..23555e34 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 013/102] 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 333f6fbe..b26dfa89 100755 --- a/tools/tests_wycheproof_generate.py +++ b/tools/tests_wycheproof_generate.py @@ -7,8 +7,6 @@ Generate a C file with ECDSA testvectors from the Wycheproof project. ''' import json -import hashlib -import urllib.request import sys filename_input = sys.argv[1] @@ -19,7 +17,8 @@ with open(filename_input) as f: 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 @@ for i in range(num_groups): 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 @@ for i in range(num_groups): 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 @@ for i in range(num_groups): 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 @@ typedef struct { 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 014/102] build: allow static or shared but not both --- CMakeLists.txt | 18 +++++--- examples/CMakeLists.txt | 10 ++-- src/CMakeLists.txt | 100 ++++++++++++++++------------------------ 3 files changed, 55 insertions(+), 73 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2ddf91ae..40e88e36 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 0884b645..ba2fe122 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 43996cc1..4758fad1 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 "") -if(SECP256K1_ASM STREQUAL "arm") - add_library(common OBJECT - asm/field_10x26_arm.s - ) - set(common_obj "$") -else() - set(common_obj "") -endif() - -add_library(precomputed OBJECT +add_library(secp256k1_precomputed OBJECT EXCLUDE_FROM_ALL precomputed_ecmult.c precomputed_ecmult_gen.c ) -set(internal_obj "$" "${common_obj}") -add_library(secp256k1 SHARED EXCLUDE_FROM_ALL - secp256k1.c - ${internal_obj} -) -target_include_directories(secp256k1 INTERFACE +# 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(secp256k1_asm_arm OBJECT EXCLUDE_FROM_ALL) + target_sources(secp256k1_asm_arm PUBLIC + asm/field_10x26_arm.s + ) + target_sources(secp256k1 PRIVATE $) + target_link_libraries(secp256k1_asm INTERFACE secp256k1_asm_arm) +endif() + +# 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() + +# 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 015/102] 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 23555e34..20024e47 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 016/102] 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 cbc35fa8..91d2bed0 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 4758fad1..cd1d6f00 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 017/102] 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 cd1d6f00..24eb0d30 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 018/102] 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 91d2bed0..92ecf317 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 019/102] 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 92ecf317..92ec611f 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 020/102] 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 f6c1f586..3af5e691 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 021/102] cmake: Use dedicated `GENERATOR_IS_MULTI_CONFIG` property Available in CMake 3.9+. --- CMakeLists.txt | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 92ec611f..5308ee25 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) - set_property(CACHE CMAKE_BUILD_TYPE PROPERTY - STRINGS "RelWithDebInfo" "Release" "Debug" "MinSizeRel" "Coverage" - ) -endif() - +get_property(is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) 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(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 "${default_build_type}" "Release" "Debug" "MinSizeRel" "Coverage" + ) + 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 022/102] 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 bc4d7b57..5a4d939b 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 023/102] cmake: Improve version comparison --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5308ee25..fe716c8b 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 024/102] 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 00000000..b35cd805 --- /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 025/102] 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 bc7e499d..574902b8 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 026/102] 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 7ec069a8..29017dc9 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 4c1946a5..9b3c92dd 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 027/102] 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 91d2bed0..0c8f049a 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 028/102] 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 bf9a932f..1564b1a1 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 029/102] 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 0c8f049a..0b588ac9 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 030/102] 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 4b57548b..d02a4d9b 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 bc5b7cb1..154e700b 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 031/102] 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 154e700b..ce991e16 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 032/102] 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 0f9c35fa..24355039 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 033/102] 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 20024e47..f745013c 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 034/102] 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 f745013c..6e2aa7fe 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 035/102] 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 6e2aa7fe..047b2f21 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 036/102] 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 047b2f21..29b8a69c 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 037/102] 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 24355039..6d46b39d 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 f980f47b..0e3faf02 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 038/102] 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 f53c252c..9a99e4f2 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 039/102] 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 fe716c8b..ac18cf83 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 9a99e4f2..1d81a931 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 040/102] cmake, doc: Document compiler flags --- CMakeLists.txt | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ac18cf83..86ffd931 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 041/102] 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 cd1d6f00..720377c8 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 042/102] 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 cd1d6f00..e97ca214 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 043/102] 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 0b904a4e..59250037 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 8120f496..e095b7f8 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 01c5f3a8..9d69c904 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 044/102] 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 59250037..5b764366 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 045/102] 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 a9a63850..73ba79ab 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 6d46b39d..da1f0132 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 046/102] 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 733fee52..cd9845c5 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 047/102] 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 833f7071..99920568 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 048/102] 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 9e065d55..080e04bc 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 f2b6f482..81e16e34 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 5a990f7d..ee60fe9f 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 049/102] 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 c7a88c4e..62dc0f3a 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 050/102] 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 29017dc9..d6031e58 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 051/102] 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 b79ba597..14cdb406 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 d6031e58..86be92d5 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 052/102] 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 62dc0f3a..dca75aac 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 6b58380f..c1647117 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 0e403f32..9b9794c0 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 14cdb406..77ad7435 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 86be92d5..48357a1c 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 053/102] 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 48357a1c..f1b62e36 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 054/102] 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 a9a63850..6f0152a8 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 f1b62e36..44d98434 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 055/102] 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 dca75aac..28ebe85a 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 9eb65607..4fe36d08 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 c1647117..8115f534 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 50ee3f9e..e4646a56 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 9b9794c0..cd240577 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 0a03076b..9920dfdb 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 056/102] 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 59250037..1560dc7d 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 cb3b4b51..a1d9eb36 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 6bf5b573..0b99aa3a 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 ad8c1a93..93844caa 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 057/102] 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 28ebe85a..3914f6b4 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 4fe36d08..203c1016 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 e4646a56..f20c246f 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 058/102] 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 3914f6b4..161df2b3 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 8115f534..537000a8 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 cd240577..820bc346 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 9920dfdb..f3341db0 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 059/102] 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 161df2b3..ba2d57bb 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 537000a8..b7611164 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 820bc346..09f3d749 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 f3341db0..3928e417 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 060/102] 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 ba2d57bb..cae92b58 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 b7611164..7043da3d 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 09f3d749..6594972d 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 3928e417..414e3e18 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 061/102] 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 cae92b58..8db62a92 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 7043da3d..e107bee8 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 6594972d..1a8960ff 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 414e3e18..ae546938 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 062/102] 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 8db62a92..e841f14e 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 e107bee8..70be960f 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 1a8960ff..c735257f 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 ae546938..0083aabc 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 063/102] 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 e841f14e..f6f3fa9f 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 70be960f..7fc9993e 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 c735257f..d2c4a6ba 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 0083aabc..0eccf750 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 064/102] 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 f6f3fa9f..c057472c 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 7fc9993e..5e934c43 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 d2c4a6ba..0572d77b 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 0eccf750..8c851340 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 065/102] 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 c057472c..9e517dca 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 5e934c43..e7305abb 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 0572d77b..31c3bcb7 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 8c851340..bd698203 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 066/102] 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 9e517dca..e7b64e78 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 bd698203..dae82aa6 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 067/102] 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 e7b64e78..4145d89c 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 e7305abb..a7a0186b 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 31c3bcb7..b4af5d69 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 dae82aa6..4424ddb1 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 068/102] 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 4145d89c..b1c434ea 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 a7a0186b..5e0b65d6 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 b4af5d69..b06b485b 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 4424ddb1..304c428c 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 069/102] 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 b1c434ea..327e63fc 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 5e0b65d6..c3f49c86 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 b06b485b..0994087c 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 304c428c..a09c7a6b 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 070/102] 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 327e63fc..b1bc4b97 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 c3f49c86..9e29f6ad 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 0994087c..4775ee0c 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 a09c7a6b..1c707951 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 071/102] 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 b1bc4b97..2c1e9d2e 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 9e29f6ad..f8c8ddb5 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 4775ee0c..f5091373 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 1c707951..8bd18c61 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 072/102] 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 2c1e9d2e..988bc6f3 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 f8c8ddb5..eefd4da6 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 f5091373..8bd084ff 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 8bd18c61..172b846d 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 073/102] 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 988bc6f3..c301841b 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 eefd4da6..f2cc4ad1 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 8bd084ff..adfac577 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 172b846d..0def1e57 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 074/102] 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 c301841b..597c9fe3 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 f2cc4ad1..f34f27bb 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 adfac577..5e90218c 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 0def1e57..ff4c8eca 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 075/102] 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 597c9fe3..eb6c586b 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 ff4c8eca..89ffc76c 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 076/102] 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 eb6c586b..daa2c540 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 f34f27bb..62191501 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 5e90218c..6a90ef4c 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 89ffc76c..bb1608d2 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 077/102] 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 daa2c540..4928e256 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 62191501..b0676eb9 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 6a90ef4c..d183b0bf 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 bb1608d2..fd0d56da 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 078/102] 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 4928e256..cb330635 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 b0676eb9..55d152ec 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 d183b0bf..1946fbb8 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 fd0d56da..0e1c7630 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 079/102] 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 cb330635..953919d9 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 55d152ec..d7b30cc8 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 1946fbb8..e056cc26 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 0e1c7630..3c03e263 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 080/102] 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 953919d9..4b23333e 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 d7b30cc8..39588c0b 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 e056cc26..d9d4e1a7 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 3c03e263..0eac34d1 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 081/102] 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 4b23333e..c20638e4 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 39588c0b..ec53165e 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 d9d4e1a7..06a2e379 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 0eac34d1..8dbc765f 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 082/102] 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 c20638e4..a515f380 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 ec53165e..80f32aa4 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 06a2e379..a9a436de 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 8dbc765f..0d46b313 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 083/102] 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 a515f380..2c8fbc28 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 80f32aa4..946c95fb 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 a9a436de..f9479036 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 0d46b313..187ffc8d 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 084/102] 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 946c95fb..3f719c16 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 f9479036..a44a64b5 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 187ffc8d..c082d8f5 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 085/102] 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 a7a2be7a..d5450e29 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 9dcb7581..6164330b 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 7af333ca..086cbc85 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 086/102] 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 88981519..2a5584ea 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 94ae22f7..f9889d53 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 087/102] 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 f2b6f482..66082e66 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 8e400b69..0ea26998 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 e33727d3..c7cef872 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 2a5584ea..e50ec3ae 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 f9889d53..da9936db 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 088/102] 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 062005ee..2da5d802 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 089/102] 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 2da5d802..ddcb8a59 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 090/102] 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 cd9845c5..1ee665fd 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 091/102] 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 da1f0132..64db038c 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 ee60fe9f..5829dad5 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 092/102] 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 | 21 ++++++++++------- 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, 69 insertions(+), 40 deletions(-) diff --git a/src/bench_internal.c b/src/bench_internal.c index c248ab8e..f3686dd2 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 90b4b22b..48e30851 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 e0506d3e..b2fe36fe 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 ff6a2992..7d672b99 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 4f5ea9f3..deb0323b 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 2c8fbc28..bbc836b1 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). - * - * Note that this function is unusual in that the normalization of the output depends on the - * run-time value of a. + * On output, r = a (mod p). It will have magnitude 1, and not be normalized. */ -static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a); +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. + * + * 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_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 3f719c16..c1b32b80 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 a44a64b5..0a4cc1a6 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 c082d8f5..72703750 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 73520044..0c7e2667 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 5ecc90d5..d3d817a1 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 e7906eb6..76a005e0 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 cd651591..4e7b45a0 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 086cbc85..41b82857 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 64db038c..70cee317 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 5829dad5..d35acdd5 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 093/102] 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 e50ec3ae..0d342fd8 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 094/102] 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 e8efa610..04a9af21 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 095/102] 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 a1d9eb36..c764e642 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 00000000..15c44b24 --- /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 00000000..d3d93470 --- /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 096/102] 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 154157ff..6d46b9e8 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 0b99aa3a..c898b923 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 097/102] Add release note --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d23662a..f1ebb6f2 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 098/102] 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 c764e642..f1dac7b2 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 6d46b9e8..11adef4f 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 3f658877..ae82cd47 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 c898b923..3db87be1 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 099/102] changelog: Add entry for #1303 --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f1ebb6f2..aa1371f1 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 100/102] 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 d5450e29..a7a2be7a 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 6164330b..9dcb7581 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 41b82857..bdbd97cc 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 101/102] changelog: Catch up --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index aa1371f1..265fb884 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 102/102] 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 265fb884..6c5dbb84 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 3db87be1..e55be150 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: