From ac71020ebe052901000e5efa7a59aad77ecfc1a0 Mon Sep 17 00:00:00 2001 From: Tim Ruffing Date: Fri, 4 Feb 2022 15:11:38 +0100 Subject: [PATCH 01/47] group: Save a normalize_to_zero in gej_add_ge The code currently switches to the alternative formula for lambda only if (R,M) = (0,0) but the alternative formula works whenever M = 0: Specifically, M = 0 implies y1 = -y2. If x1 = x2, then a = -b this is the r = infinity case that we handle separately. If x1 != x2, then the denominator in the alternative formula is non-zero, so this formula is well-defined. One needs to carefully check that the infinity assignment is still correct because now the definition of m_alt at this point in the code has changed. But this is true: Case y1 = -y2: Then degenerate = true and infinity = ((x1 - x2)Z == 0) & ~a->infinity . a->infinity is handled separately. And if ~a->infinity, then Z = Z1 != 0, so infinity = (x1 - x2 == 0) = (a == -b) by case condition. Case y1 != -y2: Then degenerate = false and infinity = ((y1 + y2)Z == 0) & ~a->infinity . a->infinity is handled separately. And if ~a->infinity, then Z = Z1 != 0, so infinity = (y1 + y2 == 0) = false by case condition. Co-Authored-By: Pieter Wuille --- sage/prove_group_implementations.sage | 23 +++++++++-------------- src/group_impl.h | 7 +++---- 2 files changed, 12 insertions(+), 18 deletions(-) diff --git a/sage/prove_group_implementations.sage b/sage/prove_group_implementations.sage index 96ce3350..b6bdfa3e 100644 --- a/sage/prove_group_implementations.sage +++ b/sage/prove_group_implementations.sage @@ -157,7 +157,7 @@ def formula_secp256k1_gej_add_ge(branch, a, b): zeroes = {} nonzeroes = {} a_infinity = False - if (branch & 4) != 0: + if (branch & 2) != 0: nonzeroes.update({a.Infinity : 'a_infinite'}) a_infinity = True else: @@ -176,15 +176,11 @@ def formula_secp256k1_gej_add_ge(branch, a, b): m_alt = -u2 tt = u1 * m_alt rr = rr + tt - degenerate = (branch & 3) == 3 - if (branch & 1) != 0: + degenerate = (branch & 1) != 0 + if degenerate: zeroes.update({m : 'm_zero'}) else: nonzeroes.update({m : 'm_nonzero'}) - if (branch & 2) != 0: - zeroes.update({rr : 'rr_zero'}) - else: - nonzeroes.update({rr : 'rr_nonzero'}) rr_alt = s1 rr_alt = rr_alt * 2 m_alt = m_alt + u1 @@ -200,12 +196,11 @@ def formula_secp256k1_gej_add_ge(branch, a, b): t = rr_alt^2 rz = a.Z * m_alt infinity = False - if (branch & 8) != 0: - if not a_infinity: - infinity = True - zeroes.update({rz : 'r.z=0'}) + if (branch & 4) != 0: + infinity = True + zeroes.update({rz : 'r.z = 0'}) else: - nonzeroes.update({rz : 'r.z!=0'}) + nonzeroes.update({rz : 'r.z != 0'}) t = t + q rx = t t = t * 2 @@ -289,14 +284,14 @@ if __name__ == "__main__": success = success & check_symbolic_jacobian_weierstrass("secp256k1_gej_add_var", 0, 7, 5, formula_secp256k1_gej_add_var) success = success & check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge_var", 0, 7, 5, formula_secp256k1_gej_add_ge_var) success = success & check_symbolic_jacobian_weierstrass("secp256k1_gej_add_zinv_var", 0, 7, 5, formula_secp256k1_gej_add_zinv_var) - success = success & check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge", 0, 7, 16, formula_secp256k1_gej_add_ge) + success = success & check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge", 0, 7, 8, formula_secp256k1_gej_add_ge) success = success & (not check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge_old [should fail]", 0, 7, 4, formula_secp256k1_gej_add_ge_old)) if len(sys.argv) >= 2 and sys.argv[1] == "--exhaustive": success = success & check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_var", 0, 7, 5, formula_secp256k1_gej_add_var, 43) success = success & check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge_var", 0, 7, 5, formula_secp256k1_gej_add_ge_var, 43) success = success & check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_zinv_var", 0, 7, 5, formula_secp256k1_gej_add_zinv_var, 43) - success = success & check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge", 0, 7, 16, formula_secp256k1_gej_add_ge, 43) + success = success & check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge", 0, 7, 8, formula_secp256k1_gej_add_ge, 43) success = success & (not check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge_old [should fail]", 0, 7, 4, formula_secp256k1_gej_add_ge_old, 43)) sys.exit(int(not success)) diff --git a/src/group_impl.h b/src/group_impl.h index b19b02a0..a028cc53 100644 --- a/src/group_impl.h +++ b/src/group_impl.h @@ -558,10 +558,9 @@ static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_fe_negate(&m_alt, &u2, 1); /* Malt = -X2*Z1^2 */ secp256k1_fe_mul(&tt, &u1, &m_alt); /* tt = -U1*U2 (2) */ secp256k1_fe_add(&rr, &tt); /* rr = R = T^2-U1*U2 (3) */ - /** If lambda = R/M = 0/0 we have a problem (except in the "trivial" + /** If lambda = R/M = R/0 we have a problem (except in the "trivial" * case that Z = z1z2 = 0, and this is special-cased later on). */ - degenerate = secp256k1_fe_normalizes_to_zero(&m) & - secp256k1_fe_normalizes_to_zero(&rr); + degenerate = secp256k1_fe_normalizes_to_zero(&m); /* This only occurs when y1 == -y2 and x1^3 == x2^3, but x1 != x2. * This means either x1 == beta*x2 or beta*x1 == x2, where beta is * a nontrivial cube root of one. In either case, an alternate @@ -573,7 +572,7 @@ static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_fe_cmov(&rr_alt, &rr, !degenerate); secp256k1_fe_cmov(&m_alt, &m, !degenerate); - /* Now Ralt / Malt = lambda and is guaranteed not to be 0/0. + /* Now Ralt / Malt = lambda and is guaranteed not to be Ralt / 0. * From here on out Ralt and Malt represent the numerator * and denominator of lambda; R and M represent the explicit * expressions x1^2 + x2^2 + x1x2 and y1 + y2. */ From e089eecc1e54551287b12539d2211da631a6ec5c Mon Sep 17 00:00:00 2001 From: Tim Ruffing Date: Fri, 4 Feb 2022 15:24:33 +0100 Subject: [PATCH 02/47] group: Further simply gej_add_ge --- sage/prove_group_implementations.sage | 11 ++++------ src/group_impl.h | 30 ++++++++++++++++++++------- 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/sage/prove_group_implementations.sage b/sage/prove_group_implementations.sage index b6bdfa3e..3aa5ad91 100644 --- a/sage/prove_group_implementations.sage +++ b/sage/prove_group_implementations.sage @@ -195,12 +195,6 @@ def formula_secp256k1_gej_add_ge(branch, a, b): n = m t = rr_alt^2 rz = a.Z * m_alt - infinity = False - if (branch & 4) != 0: - infinity = True - zeroes.update({rz : 'r.z = 0'}) - else: - nonzeroes.update({rz : 'r.z != 0'}) t = t + q rx = t t = t * 2 @@ -213,8 +207,11 @@ def formula_secp256k1_gej_add_ge(branch, a, b): rx = b.X ry = b.Y rz = 1 - if infinity: + if (branch & 4) != 0: + zeroes.update({rz : 'r.z = 0'}) return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zeroes, nonzero=nonzeroes), point_at_infinity()) + else: + nonzeroes.update({rz : 'r.z != 0'}) return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zeroes, nonzero=nonzeroes), jacobianpoint(rx, ry, rz)) def formula_secp256k1_gej_add_ge_old(branch, a, b): diff --git a/src/group_impl.h b/src/group_impl.h index a028cc53..05534d67 100644 --- a/src/group_impl.h +++ b/src/group_impl.h @@ -492,11 +492,11 @@ static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const /* Operations: 7 mul, 5 sqr, 24 add/cmov/half/mul_int/negate/normalize_weak/normalizes_to_zero */ secp256k1_fe zz, u1, u2, s1, s2, t, tt, m, n, q, rr; secp256k1_fe m_alt, rr_alt; - int infinity, degenerate; + int degenerate; VERIFY_CHECK(!b->infinity); VERIFY_CHECK(a->infinity == 0 || a->infinity == 1); - /** In: + /* In: * Eric Brier and Marc Joye, Weierstrass Elliptic Curves and Side-Channel Attacks. * In D. Naccache and P. Paillier, Eds., Public Key Cryptography, vol. 2274 of Lecture Notes in Computer Science, pages 335-345. Springer-Verlag, 2002. * we find as solution for a unified addition/doubling formula: @@ -558,8 +558,8 @@ static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_fe_negate(&m_alt, &u2, 1); /* Malt = -X2*Z1^2 */ secp256k1_fe_mul(&tt, &u1, &m_alt); /* tt = -U1*U2 (2) */ secp256k1_fe_add(&rr, &tt); /* rr = R = T^2-U1*U2 (3) */ - /** If lambda = R/M = R/0 we have a problem (except in the "trivial" - * case that Z = z1z2 = 0, and this is special-cased later on). */ + /* If lambda = R/M = R/0 we have a problem (except in the "trivial" + * case that Z = z1z2 = 0, and this is special-cased later on). */ degenerate = secp256k1_fe_normalizes_to_zero(&m); /* This only occurs when y1 == -y2 and x1^3 == x2^3, but x1 != x2. * This means either x1 == beta*x2 or beta*x1 == x2, where beta is @@ -587,7 +587,6 @@ static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_fe_cmov(&n, &m, degenerate); /* n = M^3 * Malt (2) */ secp256k1_fe_sqr(&t, &rr_alt); /* t = Ralt^2 (1) */ secp256k1_fe_mul(&r->z, &a->z, &m_alt); /* r->z = Z3 = Malt*Z (1) */ - infinity = secp256k1_fe_normalizes_to_zero(&r->z) & ~a->infinity; secp256k1_fe_add(&t, &q); /* t = Ralt^2 + Q (2) */ r->x = t; /* r->x = X3 = Ralt^2 + Q (2) */ secp256k1_fe_mul_int(&t, 2); /* t = 2*X3 (4) */ @@ -597,11 +596,28 @@ static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_fe_negate(&r->y, &t, 3); /* r->y = -(Ralt*(2*X3 + Q) + M^3*Malt) (4) */ secp256k1_fe_half(&r->y); /* r->y = Y3 = -(Ralt*(2*X3 + Q) + M^3*Malt)/2 (3) */ - /** In case a->infinity == 1, replace r with (b->x, b->y, 1). */ + /* In case a->infinity == 1, replace r with (b->x, b->y, 1). */ secp256k1_fe_cmov(&r->x, &b->x, a->infinity); secp256k1_fe_cmov(&r->y, &b->y, a->infinity); secp256k1_fe_cmov(&r->z, &secp256k1_fe_one, a->infinity); - r->infinity = infinity; + + /* Set r->infinity if r->z is 0. + * + * If a->infinity is set, then r->infinity = (r->z == 0) = (1 == 0) = false, + * which is correct because the function assumes that b is not infinity. + * + * Now assume !a->infinity. This implies Z = Z1 != 0. + * + * Case y1 = -y2: + * In this case we could have a = -b, namely if x1 = x2. + * We have degenerate = true, r->z = (x1 - x2) * Z. + * Then r->infinity = ((x1 - x2)Z == 0) = (x1 == x2) = (a == -b). + * + * Case y1 != -y2: + * In this case, we can't have a = -b. + * 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); } static void secp256k1_gej_rescale(secp256k1_gej *r, const secp256k1_fe *s) { From e862c4af0c5a7300129700d38eff499a836a108d Mon Sep 17 00:00:00 2001 From: Matt Whitlock Date: Mon, 21 Nov 2022 22:13:04 -0500 Subject: [PATCH 03/47] Makefile: add -I$(top_srcdir)/src to CPPFLAGS for precomputed When performing an out-of-source-tree build, regenerating the source files for the precomputed ecmult tables places them outside the source tree. Then, when they are to be compiled, they cannot find the headers they need because the source tree is absent from their include search path. This appears to have been an oversight, as the relevant -I options are present in libsecp256k1_la_CPPFLAGS but were missing from libsecp256k1_precomputed_la_CPPFLAGS. This commit adds them. --- Makefile.am | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index 80950130..73993488 100644 --- a/Makefile.am +++ b/Makefile.am @@ -73,7 +73,9 @@ noinst_HEADERS += examples/random.h PRECOMPUTED_LIB = libsecp256k1_precomputed.la noinst_LTLIBRARIES = $(PRECOMPUTED_LIB) libsecp256k1_precomputed_la_SOURCES = src/precomputed_ecmult.c src/precomputed_ecmult_gen.c -libsecp256k1_precomputed_la_CPPFLAGS = $(SECP_INCLUDES) $(SECP_CONFIG_DEFINES) +# We need `-I$(top_srcdir)/src` in VPATH builds if libsecp256k1_precomputed_la_SOURCES have been recreated in the build tree. +# This helps users and packagers who insist on recreating the precomputed files (e.g., Gentoo). +libsecp256k1_precomputed_la_CPPFLAGS = -I$(top_srcdir)/src $(SECP_INCLUDES) $(SECP_CONFIG_DEFINES) if USE_EXTERNAL_ASM COMMON_LIB = libsecp256k1_common.la From e03ef8655933d3e2b4830e7f8fe86deba820a073 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Mon, 9 Jan 2023 12:02:27 -0500 Subject: [PATCH 04/47] Make all non-API functions (except main) static --- src/bench.c | 2 +- src/bench.h | 12 +- src/bench_ecmult.c | 2 +- src/bench_internal.c | 55 ++-- src/modules/ecdh/bench_impl.h | 2 +- src/modules/ecdh/tests_impl.h | 14 +- src/modules/extrakeys/tests_impl.h | 16 +- src/modules/recovery/bench_impl.h | 6 +- src/modules/recovery/tests_exhaustive_impl.h | 4 +- src/modules/recovery/tests_impl.h | 8 +- src/modules/schnorrsig/bench_impl.h | 6 +- src/modules/schnorrsig/tests_impl.h | 24 +- src/tests.c | 286 +++++++++---------- src/tests_exhaustive.c | 22 +- src/valgrind_ctime_test.c | 4 +- 15 files changed, 230 insertions(+), 233 deletions(-) diff --git a/src/bench.c b/src/bench.c index e68021aa..833f7071 100644 --- a/src/bench.c +++ b/src/bench.c @@ -11,7 +11,7 @@ #include "util.h" #include "bench.h" -void help(int default_iters) { +static void help(int default_iters) { printf("Benchmarks the following algorithms:\n"); printf(" - ECDSA signing/verification\n"); diff --git a/src/bench.h b/src/bench.h index 611ba11f..bf9a932f 100644 --- a/src/bench.h +++ b/src/bench.h @@ -38,7 +38,7 @@ static int64_t gettime_i64(void) { #define FP_MULT (1000000LL) /* Format fixed point number. */ -void print_number(const int64_t x) { +static void print_number(const int64_t x) { int64_t x_abs, y; int c, i, rounding, g; /* g = integer part size, c = fractional part size */ size_t ptr; @@ -95,7 +95,7 @@ void print_number(const int64_t x) { printf("%-*s", FP_EXP, &buffer[ptr + g]); /* Prints fractional part */ } -void run_benchmark(char *name, void (*benchmark)(void*, int), void (*setup)(void*), void (*teardown)(void*, int), void* data, int count, int iter) { +static void run_benchmark(char *name, void (*benchmark)(void*, int), void (*setup)(void*), void (*teardown)(void*, int), void* data, int count, int iter) { int i; int64_t min = INT64_MAX; int64_t sum = 0; @@ -129,7 +129,7 @@ void run_benchmark(char *name, void (*benchmark)(void*, int), void (*setup)(void printf("\n"); } -int have_flag(int argc, char** argv, char *flag) { +static int have_flag(int argc, char** argv, char *flag) { char** argm = argv + argc; argv++; while (argv != argm) { @@ -145,7 +145,7 @@ int have_flag(int argc, char** argv, char *flag) { returns: - 1 if the user entered an invalid argument - 0 if all the user entered arguments are valid */ -int have_invalid_args(int argc, char** argv, char** valid_args, size_t n) { +static int have_invalid_args(int argc, char** argv, char** valid_args, size_t n) { size_t i; int found_valid; char** argm = argv + argc; @@ -167,7 +167,7 @@ int have_invalid_args(int argc, char** argv, char** valid_args, size_t n) { return 0; } -int get_iters(int default_iters) { +static int get_iters(int default_iters) { char* env = getenv("SECP256K1_BENCH_ITERS"); if (env) { return strtol(env, NULL, 0); @@ -176,7 +176,7 @@ int get_iters(int default_iters) { } } -void print_output_table_header_row(void) { +static void print_output_table_header_row(void) { char* bench_str = "Benchmark"; /* left justified */ char* min_str = " Min(us) "; /* center alignment */ char* avg_str = " Avg(us) "; diff --git a/src/bench_ecmult.c b/src/bench_ecmult.c index 9d0db340..98fb798d 100644 --- a/src/bench_ecmult.c +++ b/src/bench_ecmult.c @@ -18,7 +18,7 @@ #define POINTS 32768 -void help(char **argv) { +static void help(char **argv) { printf("Benchmark EC multiplication algorithms\n"); printf("\n"); printf("Usage: %s \n", argv[0]); diff --git a/src/bench_internal.c b/src/bench_internal.c index 2224058f..fd794a1c 100644 --- a/src/bench_internal.c +++ b/src/bench_internal.c @@ -27,7 +27,7 @@ typedef struct { int wnaf[256]; } bench_inv; -void bench_setup(void* arg) { +static void bench_setup(void* arg) { bench_inv *data = (bench_inv*)arg; static const unsigned char init[4][32] = { @@ -79,7 +79,7 @@ void bench_setup(void* arg) { memcpy(data->data + 32, init[1], 32); } -void bench_scalar_add(void* arg, int iters) { +static void bench_scalar_add(void* arg, int iters) { int i, j = 0; bench_inv *data = (bench_inv*)arg; @@ -89,7 +89,7 @@ void bench_scalar_add(void* arg, int iters) { CHECK(j <= iters); } -void bench_scalar_negate(void* arg, int iters) { +static void bench_scalar_negate(void* arg, int iters) { int i; bench_inv *data = (bench_inv*)arg; @@ -98,7 +98,7 @@ void bench_scalar_negate(void* arg, int iters) { } } -void bench_scalar_mul(void* arg, int iters) { +static void bench_scalar_mul(void* arg, int iters) { int i; bench_inv *data = (bench_inv*)arg; @@ -107,7 +107,7 @@ void bench_scalar_mul(void* arg, int iters) { } } -void bench_scalar_split(void* arg, int iters) { +static void bench_scalar_split(void* arg, int iters) { int i, j = 0; bench_inv *data = (bench_inv*)arg; @@ -118,7 +118,7 @@ void bench_scalar_split(void* arg, int iters) { CHECK(j <= iters); } -void bench_scalar_inverse(void* arg, int iters) { +static void bench_scalar_inverse(void* arg, int iters) { int i, j = 0; bench_inv *data = (bench_inv*)arg; @@ -129,7 +129,7 @@ void bench_scalar_inverse(void* arg, int iters) { CHECK(j <= iters); } -void bench_scalar_inverse_var(void* arg, int iters) { +static void bench_scalar_inverse_var(void* arg, int iters) { int i, j = 0; bench_inv *data = (bench_inv*)arg; @@ -140,7 +140,7 @@ void bench_scalar_inverse_var(void* arg, int iters) { CHECK(j <= iters); } -void bench_field_half(void* arg, int iters) { +static void bench_field_half(void* arg, int iters) { int i; bench_inv *data = (bench_inv*)arg; @@ -149,7 +149,7 @@ void bench_field_half(void* arg, int iters) { } } -void bench_field_normalize(void* arg, int iters) { +static void bench_field_normalize(void* arg, int iters) { int i; bench_inv *data = (bench_inv*)arg; @@ -158,7 +158,7 @@ void bench_field_normalize(void* arg, int iters) { } } -void bench_field_normalize_weak(void* arg, int iters) { +static void bench_field_normalize_weak(void* arg, int iters) { int i; bench_inv *data = (bench_inv*)arg; @@ -167,7 +167,7 @@ void bench_field_normalize_weak(void* arg, int iters) { } } -void bench_field_mul(void* arg, int iters) { +static void bench_field_mul(void* arg, int iters) { int i; bench_inv *data = (bench_inv*)arg; @@ -176,7 +176,7 @@ void bench_field_mul(void* arg, int iters) { } } -void bench_field_sqr(void* arg, int iters) { +static void bench_field_sqr(void* arg, int iters) { int i; bench_inv *data = (bench_inv*)arg; @@ -185,7 +185,7 @@ void bench_field_sqr(void* arg, int iters) { } } -void bench_field_inverse(void* arg, int iters) { +static void bench_field_inverse(void* arg, int iters) { int i; bench_inv *data = (bench_inv*)arg; @@ -195,7 +195,7 @@ void bench_field_inverse(void* arg, int iters) { } } -void bench_field_inverse_var(void* arg, int iters) { +static void bench_field_inverse_var(void* arg, int iters) { int i; bench_inv *data = (bench_inv*)arg; @@ -205,7 +205,7 @@ void bench_field_inverse_var(void* arg, int iters) { } } -void bench_field_sqrt(void* arg, int iters) { +static void bench_field_sqrt(void* arg, int iters) { int i, j = 0; bench_inv *data = (bench_inv*)arg; secp256k1_fe t; @@ -218,7 +218,7 @@ void bench_field_sqrt(void* arg, int iters) { CHECK(j <= iters); } -void bench_group_double_var(void* arg, int iters) { +static void bench_group_double_var(void* arg, int iters) { int i; bench_inv *data = (bench_inv*)arg; @@ -227,7 +227,7 @@ void bench_group_double_var(void* arg, int iters) { } } -void bench_group_add_var(void* arg, int iters) { +static void bench_group_add_var(void* arg, int iters) { int i; bench_inv *data = (bench_inv*)arg; @@ -236,7 +236,7 @@ void bench_group_add_var(void* arg, int iters) { } } -void bench_group_add_affine(void* arg, int iters) { +static void bench_group_add_affine(void* arg, int iters) { int i; bench_inv *data = (bench_inv*)arg; @@ -245,7 +245,7 @@ void bench_group_add_affine(void* arg, int iters) { } } -void bench_group_add_affine_var(void* arg, int iters) { +static void bench_group_add_affine_var(void* arg, int iters) { int i; bench_inv *data = (bench_inv*)arg; @@ -254,7 +254,7 @@ void bench_group_add_affine_var(void* arg, int iters) { } } -void bench_group_add_zinv_var(void* arg, int iters) { +static void bench_group_add_zinv_var(void* arg, int iters) { int i; bench_inv *data = (bench_inv*)arg; @@ -263,7 +263,7 @@ void bench_group_add_zinv_var(void* arg, int iters) { } } -void bench_group_to_affine_var(void* arg, int iters) { +static void bench_group_to_affine_var(void* arg, int iters) { int i; bench_inv *data = (bench_inv*)arg; @@ -283,7 +283,7 @@ void bench_group_to_affine_var(void* arg, int iters) { } } -void bench_ecmult_wnaf(void* arg, int iters) { +static void bench_ecmult_wnaf(void* arg, int iters) { int i, bits = 0, overflow = 0; bench_inv *data = (bench_inv*)arg; @@ -295,7 +295,7 @@ void bench_ecmult_wnaf(void* arg, int iters) { CHECK(bits <= 256*iters); } -void bench_wnaf_const(void* arg, int iters) { +static void bench_wnaf_const(void* arg, int iters) { int i, bits = 0, overflow = 0; bench_inv *data = (bench_inv*)arg; @@ -307,8 +307,7 @@ void bench_wnaf_const(void* arg, int iters) { CHECK(bits <= 256*iters); } - -void bench_sha256(void* arg, int iters) { +static void bench_sha256(void* arg, int iters) { int i; bench_inv *data = (bench_inv*)arg; secp256k1_sha256 sha; @@ -320,7 +319,7 @@ void bench_sha256(void* arg, int iters) { } } -void bench_hmac_sha256(void* arg, int iters) { +static void bench_hmac_sha256(void* arg, int iters) { int i; bench_inv *data = (bench_inv*)arg; secp256k1_hmac_sha256 hmac; @@ -332,7 +331,7 @@ void bench_hmac_sha256(void* arg, int iters) { } } -void bench_rfc6979_hmac_sha256(void* arg, int iters) { +static void bench_rfc6979_hmac_sha256(void* arg, int iters) { int i; bench_inv *data = (bench_inv*)arg; secp256k1_rfc6979_hmac_sha256 rng; @@ -343,7 +342,7 @@ void bench_rfc6979_hmac_sha256(void* arg, int iters) { } } -void bench_context(void* arg, int iters) { +static void bench_context(void* arg, int iters) { int i; (void)arg; for (i = 0; i < iters; i++) { diff --git a/src/modules/ecdh/bench_impl.h b/src/modules/ecdh/bench_impl.h index 8df15bcf..c23aaa94 100644 --- a/src/modules/ecdh/bench_impl.h +++ b/src/modules/ecdh/bench_impl.h @@ -42,7 +42,7 @@ static void bench_ecdh(void* arg, int iters) { } } -void run_ecdh_bench(int iters, int argc, char** argv) { +static void run_ecdh_bench(int iters, int argc, char** argv) { bench_ecdh_data data; int d = argc == 1; diff --git a/src/modules/ecdh/tests_impl.h b/src/modules/ecdh/tests_impl.h index ce644d57..e0de787f 100644 --- a/src/modules/ecdh/tests_impl.h +++ b/src/modules/ecdh/tests_impl.h @@ -7,7 +7,7 @@ #ifndef SECP256K1_MODULE_ECDH_TESTS_H #define SECP256K1_MODULE_ECDH_TESTS_H -int ecdh_hash_function_test_fail(unsigned char *output, const unsigned char *x, const unsigned char *y, void *data) { +static int ecdh_hash_function_test_fail(unsigned char *output, const unsigned char *x, const unsigned char *y, void *data) { (void)output; (void)x; (void)y; @@ -15,7 +15,7 @@ int ecdh_hash_function_test_fail(unsigned char *output, const unsigned char *x, return 0; } -int ecdh_hash_function_custom(unsigned char *output, const unsigned char *x, const unsigned char *y, void *data) { +static int ecdh_hash_function_custom(unsigned char *output, const unsigned char *x, const unsigned char *y, void *data) { (void)data; /* Save x and y as uncompressed public key */ output[0] = 0x04; @@ -24,7 +24,7 @@ int ecdh_hash_function_custom(unsigned char *output, const unsigned char *x, con return 1; } -void test_ecdh_api(void) { +static void test_ecdh_api(void) { /* Setup context that just counts errors */ secp256k1_context *tctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); secp256k1_pubkey point; @@ -53,7 +53,7 @@ void test_ecdh_api(void) { secp256k1_context_destroy(tctx); } -void test_ecdh_generator_basepoint(void) { +static void test_ecdh_generator_basepoint(void) { unsigned char s_one[32] = { 0 }; secp256k1_pubkey point[2]; int i; @@ -94,7 +94,7 @@ void test_ecdh_generator_basepoint(void) { } } -void test_bad_scalar(void) { +static void test_bad_scalar(void) { unsigned char s_zero[32] = { 0 }; unsigned char s_overflow[32] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, @@ -124,7 +124,7 @@ void test_bad_scalar(void) { } /** Test that ECDH(sG, 1/s) == ECDH((1/s)G, s) == ECDH(G, 1) for a few random s. */ -void test_result_basepoint(void) { +static void test_result_basepoint(void) { secp256k1_pubkey point; secp256k1_scalar rand; unsigned char s[32]; @@ -155,7 +155,7 @@ void test_result_basepoint(void) { } } -void run_ecdh_tests(void) { +static void run_ecdh_tests(void) { test_ecdh_api(); test_ecdh_generator_basepoint(); test_bad_scalar(); diff --git a/src/modules/extrakeys/tests_impl.h b/src/modules/extrakeys/tests_impl.h index dd535b9a..2ec14942 100644 --- a/src/modules/extrakeys/tests_impl.h +++ b/src/modules/extrakeys/tests_impl.h @@ -14,7 +14,7 @@ static void set_counting_callbacks(secp256k1_context *ctx0, int *ecount) { secp256k1_context_set_illegal_callback(ctx0, counting_illegal_callback_fn, ecount); } -void test_xonly_pubkey(void) { +static void test_xonly_pubkey(void) { secp256k1_pubkey pk; secp256k1_xonly_pubkey xonly_pk, xonly_pk_tmp; secp256k1_ge pk1; @@ -128,7 +128,7 @@ void test_xonly_pubkey(void) { CHECK(ecount == 2); } -void test_xonly_pubkey_comparison(void) { +static void test_xonly_pubkey_comparison(void) { unsigned char pk1_ser[32] = { 0x58, 0x84, 0xb3, 0xa2, 0x4b, 0x97, 0x37, 0x88, 0x92, 0x38, 0xa6, 0x26, 0x62, 0x52, 0x35, 0x11, 0xd0, 0x9a, 0xa1, 0x1b, 0x80, 0x0b, 0x5e, 0x93, 0x80, 0x26, 0x11, 0xef, 0x67, 0x4b, 0xd9, 0x23 @@ -164,7 +164,7 @@ void test_xonly_pubkey_comparison(void) { CHECK(ecount == 6); } -void test_xonly_pubkey_tweak(void) { +static void test_xonly_pubkey_tweak(void) { unsigned char zeros64[64] = { 0 }; unsigned char overflows[32]; unsigned char sk[32]; @@ -231,7 +231,7 @@ void test_xonly_pubkey_tweak(void) { CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0); } -void test_xonly_pubkey_tweak_check(void) { +static void test_xonly_pubkey_tweak_check(void) { unsigned char zeros64[64] = { 0 }; unsigned char overflows[32]; unsigned char sk[32]; @@ -297,7 +297,7 @@ void test_xonly_pubkey_tweak_check(void) { * additional pubkeys by calling tweak_add. Then verifies every tweak starting * from the last pubkey. */ #define N_PUBKEYS 32 -void test_xonly_pubkey_tweak_recursive(void) { +static void test_xonly_pubkey_tweak_recursive(void) { unsigned char sk[32]; secp256k1_pubkey pk[N_PUBKEYS]; unsigned char pk_serialized[32]; @@ -326,7 +326,7 @@ void test_xonly_pubkey_tweak_recursive(void) { } #undef N_PUBKEYS -void test_keypair(void) { +static void test_keypair(void) { unsigned char sk[32]; unsigned char sk_tmp[32]; unsigned char zeros96[96] = { 0 }; @@ -444,7 +444,7 @@ void test_keypair(void) { secp256k1_context_set_illegal_callback(sttc, NULL, NULL); } -void test_keypair_add(void) { +static void test_keypair_add(void) { unsigned char sk[32]; secp256k1_keypair keypair; unsigned char overflows[32]; @@ -550,7 +550,7 @@ void test_keypair_add(void) { } } -void run_extrakeys_tests(void) { +static void run_extrakeys_tests(void) { /* xonly key test cases */ test_xonly_pubkey(); test_xonly_pubkey_tweak(); diff --git a/src/modules/recovery/bench_impl.h b/src/modules/recovery/bench_impl.h index ffa00df4..57108d45 100644 --- a/src/modules/recovery/bench_impl.h +++ b/src/modules/recovery/bench_impl.h @@ -15,7 +15,7 @@ typedef struct { unsigned char sig[64]; } bench_recover_data; -void bench_recover(void* arg, int iters) { +static void bench_recover(void* arg, int iters) { int i; bench_recover_data *data = (bench_recover_data*)arg; secp256k1_pubkey pubkey; @@ -36,7 +36,7 @@ void bench_recover(void* arg, int iters) { } } -void bench_recover_setup(void* arg) { +static void bench_recover_setup(void* arg) { int i; bench_recover_data *data = (bench_recover_data*)arg; @@ -48,7 +48,7 @@ void bench_recover_setup(void* arg) { } } -void run_recovery_bench(int iters, int argc, char** argv) { +static void run_recovery_bench(int iters, int argc, char** argv) { bench_recover_data data; int d = argc == 1; diff --git a/src/modules/recovery/tests_exhaustive_impl.h b/src/modules/recovery/tests_exhaustive_impl.h index ed9386b6..e318b4ff 100644 --- a/src/modules/recovery/tests_exhaustive_impl.h +++ b/src/modules/recovery/tests_exhaustive_impl.h @@ -10,7 +10,7 @@ #include "main_impl.h" #include "../../../include/secp256k1_recovery.h" -void test_exhaustive_recovery_sign(const secp256k1_context *ctx, const secp256k1_ge *group) { +static void test_exhaustive_recovery_sign(const secp256k1_context *ctx, const secp256k1_ge *group) { int i, j, k; uint64_t iter = 0; @@ -79,7 +79,7 @@ void test_exhaustive_recovery_sign(const secp256k1_context *ctx, const secp256k1 } } -void test_exhaustive_recovery_verify(const secp256k1_context *ctx, const secp256k1_ge *group) { +static void test_exhaustive_recovery_verify(const secp256k1_context *ctx, const secp256k1_ge *group) { /* This is essentially a copy of test_exhaustive_verify, with recovery added */ int s, r, msg, key; uint64_t iter = 0; diff --git a/src/modules/recovery/tests_impl.h b/src/modules/recovery/tests_impl.h index 0769b961..2db7ca94 100644 --- a/src/modules/recovery/tests_impl.h +++ b/src/modules/recovery/tests_impl.h @@ -28,7 +28,7 @@ static int recovery_test_nonce_function(unsigned char *nonce32, const unsigned c return secp256k1_testrand_bits(1); } -void test_ecdsa_recovery_api(void) { +static void test_ecdsa_recovery_api(void) { /* Setup contexts that just count errors */ secp256k1_pubkey pubkey; secp256k1_pubkey recpubkey; @@ -127,7 +127,7 @@ void test_ecdsa_recovery_api(void) { secp256k1_context_set_illegal_callback(sttc, NULL, NULL); } -void test_ecdsa_recovery_end_to_end(void) { +static void test_ecdsa_recovery_end_to_end(void) { unsigned char extra[32] = {0x00}; unsigned char privkey[32]; unsigned char message[32]; @@ -186,7 +186,7 @@ void test_ecdsa_recovery_end_to_end(void) { } /* Tests several edge cases. */ -void test_ecdsa_recovery_edge_cases(void) { +static void test_ecdsa_recovery_edge_cases(void) { const unsigned char msg32[32] = { 'T', 'h', 'i', 's', ' ', 'i', 's', ' ', 'a', ' ', 'v', 'e', 'r', 'y', ' ', 's', @@ -359,7 +359,7 @@ void test_ecdsa_recovery_edge_cases(void) { } } -void run_recovery_tests(void) { +static void run_recovery_tests(void) { int i; for (i = 0; i < count; i++) { test_ecdsa_recovery_api(); diff --git a/src/modules/schnorrsig/bench_impl.h b/src/modules/schnorrsig/bench_impl.h index f0b0d3de..93a878ed 100644 --- a/src/modules/schnorrsig/bench_impl.h +++ b/src/modules/schnorrsig/bench_impl.h @@ -21,7 +21,7 @@ typedef struct { const unsigned char **msgs; } bench_schnorrsig_data; -void bench_schnorrsig_sign(void* arg, int iters) { +static void bench_schnorrsig_sign(void* arg, int iters) { bench_schnorrsig_data *data = (bench_schnorrsig_data *)arg; int i; unsigned char msg[MSGLEN] = {0}; @@ -34,7 +34,7 @@ void bench_schnorrsig_sign(void* arg, int iters) { } } -void bench_schnorrsig_verify(void* arg, int iters) { +static void bench_schnorrsig_verify(void* arg, int iters) { bench_schnorrsig_data *data = (bench_schnorrsig_data *)arg; int i; @@ -45,7 +45,7 @@ void bench_schnorrsig_verify(void* arg, int iters) { } } -void run_schnorrsig_bench(int iters, int argc, char** argv) { +static void run_schnorrsig_bench(int iters, int argc, char** argv) { int i; bench_schnorrsig_data data; int d = argc == 1; diff --git a/src/modules/schnorrsig/tests_impl.h b/src/modules/schnorrsig/tests_impl.h index f79d7aa0..d2b3deaf 100644 --- a/src/modules/schnorrsig/tests_impl.h +++ b/src/modules/schnorrsig/tests_impl.h @@ -12,7 +12,7 @@ /* Checks that a bit flip in the n_flip-th argument (that has n_bytes many * bytes) changes the hash function */ -void nonce_function_bip340_bitflip(unsigned char **args, size_t n_flip, size_t n_bytes, size_t msglen, size_t algolen) { +static void nonce_function_bip340_bitflip(unsigned char **args, size_t n_flip, size_t n_bytes, size_t msglen, size_t algolen) { unsigned char nonces[2][32]; CHECK(nonce_function_bip340(nonces[0], args[0], msglen, args[1], args[2], args[3], algolen, args[4]) == 1); secp256k1_testrand_flip(args[n_flip], n_bytes); @@ -23,7 +23,7 @@ void nonce_function_bip340_bitflip(unsigned char **args, size_t n_flip, size_t n /* Tests for the equality of two sha256 structs. This function only produces a * correct result if an integer multiple of 64 many bytes have been written * into the hash functions. */ -void test_sha256_eq(const secp256k1_sha256 *sha1, const secp256k1_sha256 *sha2) { +static void test_sha256_eq(const secp256k1_sha256 *sha1, const secp256k1_sha256 *sha2) { /* Is buffer fully consumed? */ CHECK((sha1->bytes & 0x3F) == 0); @@ -31,7 +31,7 @@ void test_sha256_eq(const secp256k1_sha256 *sha1, const secp256k1_sha256 *sha2) CHECK(secp256k1_memcmp_var(sha1->s, sha2->s, sizeof(sha1->s)) == 0); } -void run_nonce_function_bip340_tests(void) { +static void run_nonce_function_bip340_tests(void) { unsigned char tag[13] = "BIP0340/nonce"; unsigned char aux_tag[11] = "BIP0340/aux"; unsigned char algo[13] = "BIP0340/nonce"; @@ -114,7 +114,7 @@ void run_nonce_function_bip340_tests(void) { CHECK(secp256k1_memcmp_var(nonce_z, nonce, 32) == 0); } -void test_schnorrsig_api(void) { +static void test_schnorrsig_api(void) { unsigned char sk1[32]; unsigned char sk2[32]; unsigned char sk3[32]; @@ -203,7 +203,7 @@ void test_schnorrsig_api(void) { /* Checks that hash initialized by secp256k1_schnorrsig_sha256_tagged has the * expected state. */ -void test_schnorrsig_sha256_tagged(void) { +static void test_schnorrsig_sha256_tagged(void) { unsigned char tag[17] = "BIP0340/challenge"; secp256k1_sha256 sha; secp256k1_sha256 sha_optimized; @@ -215,7 +215,7 @@ 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. */ -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 *msg32, const unsigned char *expected_sig) { unsigned char sig[64]; secp256k1_keypair keypair; secp256k1_xonly_pubkey pk, pk_expected; @@ -232,7 +232,7 @@ void test_schnorrsig_bip_vectors_check_signing(const unsigned char *sk, const un /* Helper function for schnorrsig_bip_vectors * Checks that both verify and verify_batch (TODO) return the same value as expected. */ -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 *msg32, const unsigned char *sig, int expected) { secp256k1_xonly_pubkey pk; CHECK(secp256k1_xonly_pubkey_parse(ctx, &pk, pk_serialized)); @@ -241,7 +241,7 @@ void test_schnorrsig_bip_vectors_check_verify(const unsigned char *pk_serialized /* Test vectors according to BIP-340 ("Schnorr Signatures for secp256k1"). See * https://github.com/bitcoin/bips/blob/master/bip-0340/test-vectors.csv. */ -void test_schnorrsig_bip_vectors(void) { +static void test_schnorrsig_bip_vectors(void) { { /* Test vector 0 */ const unsigned char sk[32] = { @@ -699,7 +699,7 @@ static int nonce_function_overflowing(unsigned char *nonce32, const unsigned cha return 1; } -void test_schnorrsig_sign(void) { +static void test_schnorrsig_sign(void) { unsigned char sk[32]; secp256k1_xonly_pubkey pk; secp256k1_keypair keypair; @@ -749,7 +749,7 @@ void test_schnorrsig_sign(void) { /* Creates N_SIGS valid signatures and verifies them with verify and * verify_batch (TODO). Then flips some bits and checks that verification now * fails. */ -void test_schnorrsig_sign_verify(void) { +static void test_schnorrsig_sign_verify(void) { unsigned char sk[32]; unsigned char msg[N_SIGS][32]; unsigned char sig[N_SIGS][64]; @@ -826,7 +826,7 @@ void test_schnorrsig_sign_verify(void) { } #undef N_SIGS -void test_schnorrsig_taproot(void) { +static void test_schnorrsig_taproot(void) { unsigned char sk[32]; secp256k1_keypair keypair; secp256k1_xonly_pubkey internal_pk; @@ -862,7 +862,7 @@ void test_schnorrsig_taproot(void) { CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, output_pk_bytes, pk_parity, &internal_pk, tweak) == 1); } -void run_schnorrsig_tests(void) { +static void run_schnorrsig_tests(void) { int i; run_nonce_function_bip340_tests(); diff --git a/src/tests.c b/src/tests.c index 89246cfd..49948628 100644 --- a/src/tests.c +++ b/src/tests.c @@ -47,7 +47,7 @@ static void uncounting_illegal_callback_fn(const char* str, void* data) { (*p)--; } -void random_field_element_test(secp256k1_fe *fe) { +static void random_field_element_test(secp256k1_fe *fe) { do { unsigned char b32[32]; secp256k1_testrand256_test(b32); @@ -57,7 +57,7 @@ void random_field_element_test(secp256k1_fe *fe) { } while(1); } -void random_field_element_magnitude(secp256k1_fe *fe) { +static void random_field_element_magnitude(secp256k1_fe *fe) { secp256k1_fe zero; int n = secp256k1_testrand_int(9); secp256k1_fe_normalize(fe); @@ -73,7 +73,7 @@ void random_field_element_magnitude(secp256k1_fe *fe) { #endif } -void random_group_element_test(secp256k1_ge *ge) { +static void random_group_element_test(secp256k1_ge *ge) { secp256k1_fe fe; do { random_field_element_test(&fe); @@ -85,7 +85,7 @@ void random_group_element_test(secp256k1_ge *ge) { ge->infinity = 0; } -void random_group_element_jacobian_test(secp256k1_gej *gej, const secp256k1_ge *ge) { +static void random_group_element_jacobian_test(secp256k1_gej *gej, const secp256k1_ge *ge) { secp256k1_fe z2, z3; do { random_field_element_test(&gej->z); @@ -100,13 +100,13 @@ void random_group_element_jacobian_test(secp256k1_gej *gej, const secp256k1_ge * gej->infinity = ge->infinity; } -void random_gej_test(secp256k1_gej *gej) { +static void random_gej_test(secp256k1_gej *gej) { secp256k1_ge ge; random_group_element_test(&ge); random_group_element_jacobian_test(gej, &ge); } -void random_scalar_order_test(secp256k1_scalar *num) { +static void random_scalar_order_test(secp256k1_scalar *num) { do { unsigned char b32[32]; int overflow = 0; @@ -119,7 +119,7 @@ void random_scalar_order_test(secp256k1_scalar *num) { } while(1); } -void random_scalar_order(secp256k1_scalar *num) { +static void random_scalar_order(secp256k1_scalar *num) { do { unsigned char b32[32]; int overflow = 0; @@ -132,24 +132,24 @@ void random_scalar_order(secp256k1_scalar *num) { } while(1); } -void random_scalar_order_b32(unsigned char *b32) { +static void random_scalar_order_b32(unsigned char *b32) { secp256k1_scalar num; random_scalar_order(&num); secp256k1_scalar_get_b32(b32, &num); } -void run_selftest_tests(void) { +static void run_selftest_tests(void) { /* Test public API */ secp256k1_selftest(); } -int ecmult_gen_context_eq(const secp256k1_ecmult_gen_context *a, const secp256k1_ecmult_gen_context *b) { +static int ecmult_gen_context_eq(const secp256k1_ecmult_gen_context *a, const secp256k1_ecmult_gen_context *b) { return a->built == b->built && secp256k1_scalar_eq(&a->blind, &b->blind) && secp256k1_gej_eq_var(&a->initial, &b->initial); } -int context_eq(const secp256k1_context *a, const secp256k1_context *b) { +static int context_eq(const secp256k1_context *a, const secp256k1_context *b) { return a->declassify == b->declassify && ecmult_gen_context_eq(&a->ecmult_gen_ctx, &b->ecmult_gen_ctx) && a->illegal_callback.fn == b->illegal_callback.fn @@ -158,7 +158,7 @@ int context_eq(const secp256k1_context *a, const secp256k1_context *b) { && a->error_callback.data == b->error_callback.data; } -void run_deprecated_context_flags_test(void) { +static void run_deprecated_context_flags_test(void) { /* Check that a context created with any of the flags in the flags array is * identical to the NONE context. */ unsigned int flags[] = { SECP256K1_CONTEXT_SIGN, @@ -176,7 +176,7 @@ void run_deprecated_context_flags_test(void) { secp256k1_context_destroy(none_ctx); } -void run_ec_illegal_argument_tests(void) { +static void run_ec_illegal_argument_tests(void) { int ecount = 0; int ecount2 = 10; secp256k1_pubkey pubkey; @@ -228,7 +228,7 @@ void run_ec_illegal_argument_tests(void) { secp256k1_context_set_illegal_callback(ctx, NULL, NULL); } -void run_static_context_tests(void) { +static void run_static_context_tests(void) { int32_t dummy = 0; /* Check that deprecated secp256k1_context_no_precomp is an alias to secp256k1_context_static. */ @@ -244,7 +244,7 @@ void run_static_context_tests(void) { CHECK(sttc->illegal_callback.fn == secp256k1_default_illegal_callback_fn); } -void run_proper_context_tests(int use_prealloc) { +static void run_proper_context_tests(int use_prealloc) { int32_t dummy = 0; secp256k1_context *my_ctx; void *my_ctx_prealloc = NULL; @@ -331,7 +331,7 @@ void run_proper_context_tests(int use_prealloc) { secp256k1_context_preallocated_destroy(NULL); } -void run_scratch_tests(void) { +static void run_scratch_tests(void) { const size_t adj_alloc = ((500 + ALIGNMENT - 1) / ALIGNMENT) * ALIGNMENT; int32_t ecount = 0; @@ -415,8 +415,7 @@ void run_scratch_tests(void) { secp256k1_context_set_error_callback(ctx, NULL, NULL); } - -void run_ctz_tests(void) { +static void run_ctz_tests(void) { static const uint32_t b32[] = {1, 0xffffffff, 0x5e56968f, 0xe0d63129}; static const uint64_t b64[] = {1, 0xffffffffffffffff, 0xbcd02462139b3fc3, 0x98b5f80c769693ef}; int shift; @@ -437,7 +436,7 @@ void run_ctz_tests(void) { /***** HASH TESTS *****/ -void run_sha256_known_output_tests(void) { +static void run_sha256_known_output_tests(void) { static const char *inputs[] = { "", "abc", "message digest", "secure hash algorithm", "SHA256 is considered to be safe", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", @@ -538,7 +537,7 @@ for x in digests: print(x + ',') ``` */ -void run_sha256_counter_tests(void) { +static void run_sha256_counter_tests(void) { static const char *input = "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmno"; static const secp256k1_sha256 midstates[] = { {{0xa2b5c8bb, 0x26c88bb3, 0x2abdc3d2, 0x9def99a3, 0xdfd21a6e, 0x41fe585b, 0x7ef2c440, 0x2b79adda}, @@ -596,7 +595,7 @@ void run_sha256_counter_tests(void) { } } -void run_hmac_sha256_tests(void) { +static void run_hmac_sha256_tests(void) { static const char *keys[6] = { "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b", "\x4a\x65\x66\x65", @@ -640,7 +639,7 @@ void run_hmac_sha256_tests(void) { } } -void run_rfc6979_hmac_sha256_tests(void) { +static void run_rfc6979_hmac_sha256_tests(void) { static const unsigned char key1[65] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x00, 0x4b, 0xf5, 0x12, 0x2f, 0x34, 0x45, 0x54, 0xc5, 0x3b, 0xde, 0x2e, 0xbb, 0x8c, 0xd2, 0xb7, 0xe3, 0xd1, 0x60, 0x0a, 0xd6, 0x31, 0xc3, 0x85, 0xa5, 0xd7, 0xcc, 0xe2, 0x3c, 0x77, 0x85, 0x45, 0x9a, 0}; static const unsigned char out1[3][32] = { {0x4f, 0xe2, 0x95, 0x25, 0xb2, 0x08, 0x68, 0x09, 0x15, 0x9a, 0xcd, 0xf0, 0x50, 0x6e, 0xfb, 0x86, 0xb0, 0xec, 0x93, 0x2c, 0x7b, 0xa4, 0x42, 0x56, 0xab, 0x32, 0x1e, 0x42, 0x1e, 0x67, 0xe9, 0xfb}, @@ -681,7 +680,7 @@ void run_rfc6979_hmac_sha256_tests(void) { secp256k1_rfc6979_hmac_sha256_finalize(&rng); } -void run_tagged_sha256_tests(void) { +static void run_tagged_sha256_tests(void) { int ecount = 0; unsigned char tag[32] = { 0 }; unsigned char msg[32] = { 0 }; @@ -713,7 +712,7 @@ void run_tagged_sha256_tests(void) { /***** RANDOM TESTS *****/ -void test_rand_bits(int rand32, int bits) { +static void test_rand_bits(int rand32, int bits) { /* (1-1/2^B)^rounds[B] < 1/10^9, so rounds is the number of iterations to * get a false negative chance below once in a billion */ static const unsigned int rounds[7] = {1, 30, 73, 156, 322, 653, 1316}; @@ -748,7 +747,7 @@ void test_rand_bits(int rand32, int bits) { } /* Subrange must be a whole divisor of range, and at most 64 */ -void test_rand_int(uint32_t range, uint32_t subrange) { +static void test_rand_int(uint32_t range, uint32_t subrange) { /* (1-1/subrange)^rounds < 1/10^9 */ int rounds = (subrange * 2073) / 100; int i; @@ -764,7 +763,7 @@ void test_rand_int(uint32_t range, uint32_t subrange) { CHECK(((~x) << (64 - subrange)) == 0); } -void run_rand_bits(void) { +static void run_rand_bits(void) { size_t b; test_rand_bits(1, 32); for (b = 1; b <= 32; b++) { @@ -772,7 +771,7 @@ void run_rand_bits(void) { } } -void run_rand_int(void) { +static void run_rand_int(void) { static const uint32_t ms[] = {1, 3, 17, 1000, 13771, 999999, 33554432}; static const uint32_t ss[] = {1, 3, 6, 9, 13, 31, 64}; unsigned int m, s; @@ -786,7 +785,7 @@ void run_rand_int(void) { /***** MODINV TESTS *****/ /* Compute the modular inverse of (odd) x mod 2^64. */ -uint64_t modinv2p64(uint64_t x) { +static uint64_t modinv2p64(uint64_t x) { /* If w = 1/x mod 2^(2^L), then w*(2 - w*x) = 1/x mod 2^(2^(L+1)). See * Hacker's Delight second edition, Henry S. Warren, Jr., pages 245-247 for * why. Start with L=0, for which it is true for every odd x that @@ -803,7 +802,7 @@ uint64_t modinv2p64(uint64_t x) { * * Out is a 512-bit number (represented as 32 uint16_t's in LE order). The other * arguments are 256-bit numbers (represented as 16 uint16_t's in LE order). */ -void mulmod256(uint16_t* out, const uint16_t* a, const uint16_t* b, const uint16_t* m) { +static void mulmod256(uint16_t* out, const uint16_t* a, const uint16_t* b, const uint16_t* m) { uint16_t mul[32]; uint64_t c = 0; int i, j; @@ -887,7 +886,7 @@ void mulmod256(uint16_t* out, const uint16_t* a, const uint16_t* b, const uint16 } /* Convert a 256-bit number represented as 16 uint16_t's to signed30 notation. */ -void uint16_to_signed30(secp256k1_modinv32_signed30* out, const uint16_t* in) { +static void uint16_to_signed30(secp256k1_modinv32_signed30* out, const uint16_t* in) { int i; memset(out->v, 0, sizeof(out->v)); for (i = 0; i < 256; ++i) { @@ -896,7 +895,7 @@ void uint16_to_signed30(secp256k1_modinv32_signed30* out, const uint16_t* in) { } /* Convert a 256-bit number in signed30 notation to a representation as 16 uint16_t's. */ -void signed30_to_uint16(uint16_t* out, const secp256k1_modinv32_signed30* in) { +static void signed30_to_uint16(uint16_t* out, const secp256k1_modinv32_signed30* in) { int i; memset(out, 0, 32); for (i = 0; i < 256; ++i) { @@ -905,7 +904,7 @@ void signed30_to_uint16(uint16_t* out, const secp256k1_modinv32_signed30* in) { } /* Randomly mutate the sign of limbs in signed30 representation, without changing the value. */ -void mutate_sign_signed30(secp256k1_modinv32_signed30* x) { +static void mutate_sign_signed30(secp256k1_modinv32_signed30* x) { int i; for (i = 0; i < 16; ++i) { int pos = secp256k1_testrand_bits(3); @@ -920,7 +919,7 @@ void mutate_sign_signed30(secp256k1_modinv32_signed30* x) { } /* Test secp256k1_modinv32{_var}, using inputs in 16-bit limb format, and returning inverse. */ -void test_modinv32_uint16(uint16_t* out, const uint16_t* in, const uint16_t* mod) { +static void test_modinv32_uint16(uint16_t* out, const uint16_t* in, const uint16_t* mod) { uint16_t tmp[16]; secp256k1_modinv32_signed30 x; secp256k1_modinv32_modinfo m; @@ -958,7 +957,7 @@ void test_modinv32_uint16(uint16_t* out, const uint16_t* in, const uint16_t* mod #ifdef SECP256K1_WIDEMUL_INT128 /* Convert a 256-bit number represented as 16 uint16_t's to signed62 notation. */ -void uint16_to_signed62(secp256k1_modinv64_signed62* out, const uint16_t* in) { +static void uint16_to_signed62(secp256k1_modinv64_signed62* out, const uint16_t* in) { int i; memset(out->v, 0, sizeof(out->v)); for (i = 0; i < 256; ++i) { @@ -967,7 +966,7 @@ void uint16_to_signed62(secp256k1_modinv64_signed62* out, const uint16_t* in) { } /* Convert a 256-bit number in signed62 notation to a representation as 16 uint16_t's. */ -void signed62_to_uint16(uint16_t* out, const secp256k1_modinv64_signed62* in) { +static void signed62_to_uint16(uint16_t* out, const secp256k1_modinv64_signed62* in) { int i; memset(out, 0, 32); for (i = 0; i < 256; ++i) { @@ -976,7 +975,7 @@ void signed62_to_uint16(uint16_t* out, const secp256k1_modinv64_signed62* in) { } /* Randomly mutate the sign of limbs in signed62 representation, without changing the value. */ -void mutate_sign_signed62(secp256k1_modinv64_signed62* x) { +static void mutate_sign_signed62(secp256k1_modinv64_signed62* x) { static const int64_t M62 = (int64_t)(UINT64_MAX >> 2); int i; for (i = 0; i < 8; ++i) { @@ -992,7 +991,7 @@ void mutate_sign_signed62(secp256k1_modinv64_signed62* x) { } /* Test secp256k1_modinv64{_var}, using inputs in 16-bit limb format, and returning inverse. */ -void test_modinv64_uint16(uint16_t* out, const uint16_t* in, const uint16_t* mod) { +static void test_modinv64_uint16(uint16_t* out, const uint16_t* in, const uint16_t* mod) { static const int64_t M62 = (int64_t)(UINT64_MAX >> 2); uint16_t tmp[16]; secp256k1_modinv64_signed62 x; @@ -1031,7 +1030,7 @@ void test_modinv64_uint16(uint16_t* out, const uint16_t* in, const uint16_t* mod #endif /* test if a and b are coprime */ -int coprime(const uint16_t* a, const uint16_t* b) { +static int coprime(const uint16_t* a, const uint16_t* b) { uint16_t x[16], y[16], t[16]; int i; int iszero; @@ -1061,7 +1060,7 @@ int coprime(const uint16_t* a, const uint16_t* b) { return 1; } -void run_modinv_tests(void) { +static void run_modinv_tests(void) { /* Fixed test cases. Each tuple is (input, modulus, output), each as 16x16 bits in LE order. */ static const uint16_t CASES[][3][16] = { /* Test cases triggering edge cases in divsteps */ @@ -1701,7 +1700,7 @@ void run_modinv_tests(void) { #ifdef SECP256K1_WIDEMUL_INT128 /* Add two 256-bit numbers (represented as 16 uint16_t's in LE order) together mod 2^256. */ -void add256(uint16_t* out, const uint16_t* a, const uint16_t* b) { +static void add256(uint16_t* out, const uint16_t* a, const uint16_t* b) { int i; uint32_t carry = 0; for (i = 0; i < 16; ++i) { @@ -1713,7 +1712,7 @@ void add256(uint16_t* out, const uint16_t* a, const uint16_t* b) { } /* Negate a 256-bit number (represented as 16 uint16_t's in LE order) mod 2^256. */ -void neg256(uint16_t* out, const uint16_t* a) { +static void neg256(uint16_t* out, const uint16_t* a) { int i; uint32_t carry = 1; for (i = 0; i < 16; ++i) { @@ -1724,7 +1723,7 @@ void neg256(uint16_t* out, const uint16_t* a) { } /* Right-shift a 256-bit number (represented as 16 uint16_t's in LE order). */ -void rshift256(uint16_t* out, const uint16_t* a, int n, int sign_extend) { +static void rshift256(uint16_t* out, const uint16_t* a, int n, int sign_extend) { uint16_t sign = sign_extend && (a[15] >> 15); int i, j; for (i = 15; i >= 0; --i) { @@ -1742,7 +1741,7 @@ void rshift256(uint16_t* out, const uint16_t* a, int n, int sign_extend) { } /* Load a 64-bit unsigned integer into an array of 16 uint16_t's in LE order representing a 256-bit value. */ -void load256u64(uint16_t* out, uint64_t v, int is_signed) { +static void load256u64(uint16_t* out, uint64_t v, int is_signed) { int i; uint64_t sign = is_signed && (v >> 63) ? UINT64_MAX : 0; for (i = 0; i < 4; ++i) { @@ -1754,7 +1753,7 @@ void load256u64(uint16_t* out, uint64_t v, int is_signed) { } /* Load a 128-bit unsigned integer into an array of 16 uint16_t's in LE order representing a 256-bit value. */ -void load256two64(uint16_t* out, uint64_t hi, uint64_t lo, int is_signed) { +static void load256two64(uint16_t* out, uint64_t hi, uint64_t lo, int is_signed) { int i; uint64_t sign = is_signed && (hi >> 63) ? UINT64_MAX : 0; for (i = 0; i < 4; ++i) { @@ -1769,7 +1768,7 @@ void load256two64(uint16_t* out, uint64_t hi, uint64_t lo, int is_signed) { } /* Check whether the 256-bit value represented by array of 16-bit values is in range -2^127 < v < 2^127. */ -int int256is127(const uint16_t* v) { +static int int256is127(const uint16_t* v) { int all_0 = ((v[7] & 0x8000) == 0), all_1 = ((v[7] & 0x8000) == 0x8000); int i; for (i = 8; i < 16; ++i) { @@ -1779,12 +1778,12 @@ int int256is127(const uint16_t* v) { return all_0 || all_1; } -void load256u128(uint16_t* out, const secp256k1_uint128* v) { +static void load256u128(uint16_t* out, const secp256k1_uint128* v) { uint64_t lo = secp256k1_u128_to_u64(v), hi = secp256k1_u128_hi_u64(v); load256two64(out, hi, lo, 0); } -void load256i128(uint16_t* out, const secp256k1_int128* v) { +static void load256i128(uint16_t* out, const secp256k1_int128* v) { uint64_t lo; int64_t hi; secp256k1_int128 c = *v; @@ -1794,7 +1793,7 @@ void load256i128(uint16_t* out, const secp256k1_int128* v) { load256two64(out, hi, lo, 1); } -void run_int128_test_case(void) { +static void run_int128_test_case(void) { unsigned char buf[32]; uint64_t v[4]; secp256k1_int128 swa, swz; @@ -1956,7 +1955,7 @@ void run_int128_test_case(void) { } } -void run_int128_tests(void) { +static void run_int128_tests(void) { { /* secp256k1_u128_accum_mul */ secp256k1_uint128 res; @@ -1999,7 +1998,7 @@ void run_int128_tests(void) { /***** SCALAR TESTS *****/ -void scalar_test(void) { +static void scalar_test(void) { secp256k1_scalar s; secp256k1_scalar s1; secp256k1_scalar s2; @@ -2164,7 +2163,7 @@ void scalar_test(void) { } -void run_scalar_set_b32_seckey_tests(void) { +static void run_scalar_set_b32_seckey_tests(void) { unsigned char b32[32]; secp256k1_scalar s1; secp256k1_scalar s2; @@ -2181,7 +2180,7 @@ void run_scalar_set_b32_seckey_tests(void) { CHECK(secp256k1_scalar_set_b32_seckey(&s2, b32) == 0); } -void run_scalar_tests(void) { +static void run_scalar_tests(void) { int i; for (i = 0; i < 128 * count; i++) { scalar_test(); @@ -2789,7 +2788,7 @@ void run_scalar_tests(void) { /***** FIELD TESTS *****/ -void random_fe(secp256k1_fe *x) { +static void random_fe(secp256k1_fe *x) { unsigned char bin[32]; do { secp256k1_testrand256(bin); @@ -2799,7 +2798,7 @@ void random_fe(secp256k1_fe *x) { } while(1); } -void random_fe_test(secp256k1_fe *x) { +static void random_fe_test(secp256k1_fe *x) { unsigned char bin[32]; do { secp256k1_testrand256_test(bin); @@ -2809,7 +2808,7 @@ void random_fe_test(secp256k1_fe *x) { } while(1); } -void random_fe_non_zero(secp256k1_fe *nz) { +static void random_fe_non_zero(secp256k1_fe *nz) { int tries = 10; while (--tries >= 0) { random_fe(nz); @@ -2822,7 +2821,7 @@ void random_fe_non_zero(secp256k1_fe *nz) { CHECK(tries >= 0); } -void random_fe_non_square(secp256k1_fe *ns) { +static void random_fe_non_square(secp256k1_fe *ns) { secp256k1_fe r; random_fe_non_zero(ns); if (secp256k1_fe_sqrt(&r, ns)) { @@ -2830,7 +2829,7 @@ void random_fe_non_square(secp256k1_fe *ns) { } } -int check_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b) { +static int check_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b) { secp256k1_fe an = *a; secp256k1_fe bn = *b; secp256k1_fe_normalize_weak(&an); @@ -2838,7 +2837,7 @@ int check_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b) { return secp256k1_fe_equal_var(&an, &bn); } -void run_field_convert(void) { +static void run_field_convert(void) { static const unsigned char b32[32] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, @@ -2869,7 +2868,7 @@ void run_field_convert(void) { } /* Returns true if two field elements have the same representation. */ -int fe_identical(const secp256k1_fe *a, const secp256k1_fe *b) { +static int fe_identical(const secp256k1_fe *a, const secp256k1_fe *b) { int ret = 1; #ifdef VERIFY ret &= (a->magnitude == b->magnitude); @@ -2880,7 +2879,7 @@ int fe_identical(const secp256k1_fe *a, const secp256k1_fe *b) { return ret; } -void run_field_half(void) { +static void run_field_half(void) { secp256k1_fe t, u; int m; @@ -2929,7 +2928,7 @@ void run_field_half(void) { } } -void run_field_misc(void) { +static void run_field_misc(void) { secp256k1_fe x; secp256k1_fe y; secp256k1_fe z; @@ -3021,7 +3020,7 @@ void run_field_misc(void) { } } -void test_fe_mul(const secp256k1_fe* a, const secp256k1_fe* b, int use_sqr) +static void test_fe_mul(const secp256k1_fe* a, const secp256k1_fe* b, int use_sqr) { secp256k1_fe c, an, bn; /* Variables in BE 32-byte format. */ @@ -3064,7 +3063,7 @@ void test_fe_mul(const secp256k1_fe* a, const secp256k1_fe* b, int use_sqr) CHECK(secp256k1_memcmp_var(t16, c16, 32) == 0); } -void run_fe_mul(void) { +static void run_fe_mul(void) { int i; for (i = 0; i < 100 * count; ++i) { secp256k1_fe a, b, c, d; @@ -3085,7 +3084,7 @@ void run_fe_mul(void) { } } -void run_sqr(void) { +static void run_sqr(void) { secp256k1_fe x, s; { @@ -3101,7 +3100,7 @@ void run_sqr(void) { } } -void test_sqrt(const secp256k1_fe *a, const secp256k1_fe *k) { +static void test_sqrt(const secp256k1_fe *a, const secp256k1_fe *k) { secp256k1_fe r1, r2; int v = secp256k1_fe_sqrt(&r1, a); CHECK((v == 0) == (k == NULL)); @@ -3115,7 +3114,7 @@ void test_sqrt(const secp256k1_fe *a, const secp256k1_fe *k) { } } -void run_sqrt(void) { +static void run_sqrt(void) { secp256k1_fe ns, x, s, t; int i; @@ -3168,7 +3167,7 @@ static const secp256k1_fe fe_minus_one = SECP256K1_FE_CONST( * for x!=0 and x!=1: 1/(1/x - 1) + 1 == -1/(x-1) */ -void test_inverse_scalar(secp256k1_scalar* out, const secp256k1_scalar* x, int var) +static void test_inverse_scalar(secp256k1_scalar* out, const secp256k1_scalar* x, int var) { secp256k1_scalar l, r, t; @@ -3190,7 +3189,7 @@ void test_inverse_scalar(secp256k1_scalar* out, const secp256k1_scalar* x, int v CHECK(secp256k1_scalar_is_zero(&l)); /* l == 0 */ } -void test_inverse_field(secp256k1_fe* out, const secp256k1_fe* x, int var) +static void test_inverse_field(secp256k1_fe* out, const secp256k1_fe* x, int var) { secp256k1_fe l, r, t; @@ -3215,7 +3214,7 @@ void test_inverse_field(secp256k1_fe* out, const secp256k1_fe* x, int var) CHECK(secp256k1_fe_normalizes_to_zero_var(&l)); /* l == 0 */ } -void run_inverse_tests(void) +static void run_inverse_tests(void) { /* Fixed test cases for field inverses: pairs of (x, 1/x) mod p. */ static const secp256k1_fe fe_cases[][2] = { @@ -3463,7 +3462,7 @@ void run_inverse_tests(void) /***** GROUP TESTS *****/ -void ge_equals_ge(const secp256k1_ge *a, const secp256k1_ge *b) { +static void ge_equals_ge(const secp256k1_ge *a, const secp256k1_ge *b) { CHECK(a->infinity == b->infinity); if (a->infinity) { return; @@ -3473,7 +3472,7 @@ void ge_equals_ge(const secp256k1_ge *a, const secp256k1_ge *b) { } /* This compares jacobian points including their Z, not just their geometric meaning. */ -int gej_xyz_equals_gej(const secp256k1_gej *a, const secp256k1_gej *b) { +static int gej_xyz_equals_gej(const secp256k1_gej *a, const secp256k1_gej *b) { secp256k1_gej a2; secp256k1_gej b2; int ret = 1; @@ -3494,7 +3493,7 @@ int gej_xyz_equals_gej(const secp256k1_gej *a, const secp256k1_gej *b) { return ret; } -void ge_equals_gej(const secp256k1_ge *a, const secp256k1_gej *b) { +static void ge_equals_gej(const secp256k1_ge *a, const secp256k1_gej *b) { secp256k1_fe z2s; secp256k1_fe u1, u2, s1, s2; CHECK(a->infinity == b->infinity); @@ -3511,7 +3510,7 @@ void ge_equals_gej(const secp256k1_ge *a, const secp256k1_gej *b) { CHECK(secp256k1_fe_equal_var(&s1, &s2)); } -void test_ge(void) { +static void test_ge(void) { int i, i1; int runs = 6; /* 25 points are used: @@ -3710,8 +3709,7 @@ void test_ge(void) { free(gej); } - -void test_intialized_inf(void) { +static void test_intialized_inf(void) { secp256k1_ge p; secp256k1_gej pj, npj, infj1, infj2, infj3; secp256k1_fe zinv; @@ -3743,7 +3741,7 @@ void test_intialized_inf(void) { } -void test_add_neg_y_diff_x(void) { +static void test_add_neg_y_diff_x(void) { /* The point of this test is to check that we can add two points * whose y-coordinates are negatives of each other but whose x * coordinates differ. If the x-coordinates were the same, these @@ -3810,7 +3808,7 @@ void test_add_neg_y_diff_x(void) { ge_equals_gej(&res, &sumj); } -void run_ge(void) { +static void run_ge(void) { int i; for (i = 0; i < count * 32; i++) { test_ge(); @@ -3819,7 +3817,7 @@ void run_ge(void) { test_intialized_inf(); } -void test_gej_cmov(const secp256k1_gej *a, const secp256k1_gej *b) { +static void test_gej_cmov(const secp256k1_gej *a, const secp256k1_gej *b) { secp256k1_gej t = *a; secp256k1_gej_cmov(&t, b, 0); CHECK(gej_xyz_equals_gej(&t, a)); @@ -3827,7 +3825,7 @@ void test_gej_cmov(const secp256k1_gej *a, const secp256k1_gej *b) { CHECK(gej_xyz_equals_gej(&t, b)); } -void run_gej(void) { +static void run_gej(void) { int i; secp256k1_gej a, b; @@ -3866,7 +3864,7 @@ void run_gej(void) { } } -void test_ec_combine(void) { +static void test_ec_combine(void) { secp256k1_scalar sum = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); secp256k1_pubkey data[6]; const secp256k1_pubkey* d[6]; @@ -3891,14 +3889,14 @@ void test_ec_combine(void) { } } -void run_ec_combine(void) { +static void run_ec_combine(void) { int i; for (i = 0; i < count * 8; i++) { test_ec_combine(); } } -void test_group_decompress(const secp256k1_fe* x) { +static void test_group_decompress(const secp256k1_fe* x) { /* The input itself, normalized. */ secp256k1_fe fex = *x; /* Results of set_xo_var(..., 0), set_xo_var(..., 1). */ @@ -3933,7 +3931,7 @@ void test_group_decompress(const secp256k1_fe* x) { } } -void run_group_decompress(void) { +static void run_group_decompress(void) { int i; for (i = 0; i < count * 4; i++) { secp256k1_fe fe; @@ -3944,7 +3942,7 @@ void run_group_decompress(void) { /***** ECMULT TESTS *****/ -void test_pre_g_table(const secp256k1_ge_storage * pre_g, size_t n) { +static void test_pre_g_table(const secp256k1_ge_storage * pre_g, size_t n) { /* Tests the pre_g / pre_g_128 tables for consistency. * For independent verification we take a "geometric" approach to verification. * We check that every entry is on-curve. @@ -3994,7 +3992,7 @@ void test_pre_g_table(const secp256k1_ge_storage * pre_g, size_t n) { } } -void run_ecmult_pre_g(void) { +static void run_ecmult_pre_g(void) { secp256k1_ge_storage gs; secp256k1_gej gj; secp256k1_ge g; @@ -4018,7 +4016,7 @@ void run_ecmult_pre_g(void) { CHECK(secp256k1_memcmp_var(&gs, &secp256k1_pre_g_128[0], sizeof(gs)) == 0); } -void run_ecmult_chain(void) { +static void run_ecmult_chain(void) { /* random starting point A (on the curve) */ secp256k1_gej a = SECP256K1_GEJ_CONST( 0x8b30bbe9, 0xae2a9906, 0x96b22f67, 0x0709dff3, @@ -4077,7 +4075,7 @@ void run_ecmult_chain(void) { CHECK(secp256k1_gej_eq_var(&x, &x2)); } -void test_point_times_order(const secp256k1_gej *point) { +static void test_point_times_order(const secp256k1_gej *point) { /* X * (point + G) + (order-X) * (pointer + G) = 0 */ secp256k1_scalar x; secp256k1_scalar nx; @@ -4141,7 +4139,7 @@ static const secp256k1_scalar scalars_near_split_bounds[20] = { SECP256K1_SCALAR_CONST(0x26c75a99, 0x80b861c1, 0x4a4c3805, 0x1024c8b4, 0x704d760e, 0xe95e7cd3, 0xde1bfdb1, 0xce2c5a45) }; -void test_ecmult_target(const secp256k1_scalar* target, int mode) { +static void test_ecmult_target(const secp256k1_scalar* target, int mode) { /* Mode: 0=ecmult_gen, 1=ecmult, 2=ecmult_const */ secp256k1_scalar n1, n2; secp256k1_ge p; @@ -4180,7 +4178,7 @@ void test_ecmult_target(const secp256k1_scalar* target, int mode) { CHECK(secp256k1_gej_is_infinity(&ptj)); } -void run_ecmult_near_split_bound(void) { +static void run_ecmult_near_split_bound(void) { int i; unsigned j; for (i = 0; i < 4*count; ++i) { @@ -4192,7 +4190,7 @@ void run_ecmult_near_split_bound(void) { } } -void run_point_times_order(void) { +static void run_point_times_order(void) { int i; secp256k1_fe x = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 2); static const secp256k1_fe xr = SECP256K1_FE_CONST( @@ -4213,7 +4211,7 @@ void run_point_times_order(void) { CHECK(secp256k1_fe_equal_var(&x, &xr)); } -void ecmult_const_random_mult(void) { +static void ecmult_const_random_mult(void) { /* random starting point A (on the curve) */ secp256k1_ge a = SECP256K1_GE_CONST( 0x6d986544, 0x57ff52b8, 0xcf1b8126, 0x5b802a5b, @@ -4240,7 +4238,7 @@ void ecmult_const_random_mult(void) { ge_equals_gej(&expected_b, &b); } -void ecmult_const_commutativity(void) { +static void ecmult_const_commutativity(void) { secp256k1_scalar a; secp256k1_scalar b; secp256k1_gej res1; @@ -4261,7 +4259,7 @@ void ecmult_const_commutativity(void) { ge_equals_ge(&mid1, &mid2); } -void ecmult_const_mult_zero_one(void) { +static void ecmult_const_mult_zero_one(void) { secp256k1_scalar zero = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); secp256k1_scalar one = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1); secp256k1_scalar negone; @@ -4283,7 +4281,7 @@ void ecmult_const_mult_zero_one(void) { ge_equals_ge(&res2, &point); } -void ecmult_const_chain_multiply(void) { +static void ecmult_const_chain_multiply(void) { /* Check known result (randomly generated test problem from sage) */ const secp256k1_scalar scalar = SECP256K1_SCALAR_CONST( 0x4968d524, 0x2abf9b7a, 0x466abbcf, 0x34b11b6d, @@ -4309,7 +4307,7 @@ void ecmult_const_chain_multiply(void) { ge_equals_gej(&res, &expected_point); } -void run_ecmult_const_tests(void) { +static void run_ecmult_const_tests(void) { ecmult_const_mult_zero_one(); ecmult_const_random_mult(); ecmult_const_commutativity(); @@ -4336,7 +4334,7 @@ static int ecmult_multi_false_callback(secp256k1_scalar *sc, secp256k1_ge *pt, s return 0; } -void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func ecmult_multi) { +static void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func ecmult_multi) { int ncount; secp256k1_scalar szero; secp256k1_scalar sc[32]; @@ -4561,7 +4559,7 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e } } -int test_ecmult_multi_random(secp256k1_scratch *scratch) { +static int test_ecmult_multi_random(secp256k1_scratch *scratch) { /* Large random test for ecmult_multi_* functions which exercises: * - Few or many inputs (0 up to 128, roughly exponentially distributed). * - Few or many 0*P or a*INF inputs (roughly uniformly distributed). @@ -4727,7 +4725,7 @@ int test_ecmult_multi_random(secp256k1_scratch *scratch) { return mults; } -void test_ecmult_multi_batch_single(secp256k1_ecmult_multi_func ecmult_multi) { +static void test_ecmult_multi_batch_single(secp256k1_ecmult_multi_func ecmult_multi) { secp256k1_scalar szero; secp256k1_scalar sc; secp256k1_ge pt; @@ -4747,7 +4745,7 @@ void test_ecmult_multi_batch_single(secp256k1_ecmult_multi_func ecmult_multi) { secp256k1_scratch_destroy(&ctx->error_callback, scratch_empty); } -void test_secp256k1_pippenger_bucket_window_inv(void) { +static void test_secp256k1_pippenger_bucket_window_inv(void) { int i; CHECK(secp256k1_pippenger_bucket_window_inv(0) == 0); @@ -4767,7 +4765,7 @@ void test_secp256k1_pippenger_bucket_window_inv(void) { * Probabilistically test the function returning the maximum number of possible points * for a given scratch space. */ -void test_ecmult_multi_pippenger_max_points(void) { +static void test_ecmult_multi_pippenger_max_points(void) { size_t scratch_size = secp256k1_testrand_bits(8); size_t max_size = secp256k1_pippenger_scratch_size(secp256k1_pippenger_bucket_window_inv(PIPPENGER_MAX_BUCKET_WINDOW-1)+512, 12); secp256k1_scratch *scratch; @@ -4800,7 +4798,7 @@ void test_ecmult_multi_pippenger_max_points(void) { CHECK(bucket_window == PIPPENGER_MAX_BUCKET_WINDOW); } -void test_ecmult_multi_batch_size_helper(void) { +static void test_ecmult_multi_batch_size_helper(void) { size_t n_batches, n_batch_points, max_n_batch_points, n; max_n_batch_points = 0; @@ -4848,7 +4846,7 @@ void test_ecmult_multi_batch_size_helper(void) { * Run secp256k1_ecmult_multi_var with num points and a scratch space restricted to * 1 <= i <= num points. */ -void test_ecmult_multi_batching(void) { +static void test_ecmult_multi_batching(void) { static const int n_points = 2*ECMULT_PIPPENGER_THRESHOLD; secp256k1_scalar scG; secp256k1_scalar szero; @@ -4915,7 +4913,7 @@ void test_ecmult_multi_batching(void) { free(pt); } -void run_ecmult_multi_tests(void) { +static void run_ecmult_multi_tests(void) { secp256k1_scratch *scratch; int64_t todo = (int64_t)320 * count; @@ -4942,7 +4940,7 @@ void run_ecmult_multi_tests(void) { test_ecmult_multi_batching(); } -void test_wnaf(const secp256k1_scalar *number, int w) { +static void test_wnaf(const secp256k1_scalar *number, int w) { secp256k1_scalar x, two, t; int wnaf[256]; int zeroes = -1; @@ -4976,7 +4974,7 @@ void test_wnaf(const secp256k1_scalar *number, int w) { CHECK(secp256k1_scalar_eq(&x, number)); /* check that wnaf represents number */ } -void test_constant_wnaf_negate(const secp256k1_scalar *number) { +static void test_constant_wnaf_negate(const secp256k1_scalar *number) { secp256k1_scalar neg1 = *number; secp256k1_scalar neg2 = *number; int sign1 = 1; @@ -4991,7 +4989,7 @@ void test_constant_wnaf_negate(const secp256k1_scalar *number) { CHECK(secp256k1_scalar_eq(&neg1, &neg2)); } -void test_constant_wnaf(const secp256k1_scalar *number, int w) { +static void test_constant_wnaf(const secp256k1_scalar *number, int w) { secp256k1_scalar x, shift; int wnaf[256] = {0}; int i; @@ -5031,7 +5029,7 @@ void test_constant_wnaf(const secp256k1_scalar *number, int w) { CHECK(secp256k1_scalar_eq(&x, &num)); } -void test_fixed_wnaf(const secp256k1_scalar *number, int w) { +static void test_fixed_wnaf(const secp256k1_scalar *number, int w) { secp256k1_scalar x, shift; int wnaf[256] = {0}; int i; @@ -5068,7 +5066,7 @@ void test_fixed_wnaf(const secp256k1_scalar *number, int w) { /* Checks that the first 8 elements of wnaf are equal to wnaf_expected and the * rest is 0.*/ -void test_fixed_wnaf_small_helper(int *wnaf, int *wnaf_expected, int w) { +static void test_fixed_wnaf_small_helper(int *wnaf, int *wnaf_expected, int w) { int i; for (i = WNAF_SIZE(w)-1; i >= 8; --i) { CHECK(wnaf[i] == 0); @@ -5078,7 +5076,7 @@ void test_fixed_wnaf_small_helper(int *wnaf, int *wnaf_expected, int w) { } } -void test_fixed_wnaf_small(void) { +static void test_fixed_wnaf_small(void) { int w = 4; int wnaf[256] = {0}; int i; @@ -5132,7 +5130,7 @@ void test_fixed_wnaf_small(void) { } } -void run_wnaf(void) { +static void run_wnaf(void) { int i; secp256k1_scalar n = {{0}}; @@ -5186,7 +5184,7 @@ static int test_ecmult_accumulate_cb(secp256k1_scalar* sc, secp256k1_ge* pt, siz return 1; } -void test_ecmult_accumulate(secp256k1_sha256* acc, const secp256k1_scalar* x, secp256k1_scratch* scratch) { +static void test_ecmult_accumulate(secp256k1_sha256* acc, const secp256k1_scalar* x, secp256k1_scratch* scratch) { /* Compute x*G in 6 different ways, serialize it uncompressed, and feed it into acc. */ secp256k1_gej rj1, rj2, rj3, rj4, rj5, rj6, gj, infj; secp256k1_ge r; @@ -5219,7 +5217,7 @@ void test_ecmult_accumulate(secp256k1_sha256* acc, const secp256k1_scalar* x, se } } -void test_ecmult_constants_2bit(void) { +static void test_ecmult_constants_2bit(void) { /* Using test_ecmult_accumulate, test ecmult for: * - For i in 0..36: * - Key i @@ -5263,7 +5261,7 @@ void test_ecmult_constants_2bit(void) { secp256k1_scratch_space_destroy(ctx, scratch); } -void test_ecmult_constants_sha(uint32_t prefix, size_t iter, const unsigned char* expected32) { +static void test_ecmult_constants_sha(uint32_t prefix, size_t iter, const unsigned char* expected32) { /* Using test_ecmult_accumulate, test ecmult for: * - Key 0 * - Key 1 @@ -5306,7 +5304,7 @@ void test_ecmult_constants_sha(uint32_t prefix, size_t iter, const unsigned char secp256k1_scratch_space_destroy(ctx, scratch); } -void run_ecmult_constants(void) { +static void run_ecmult_constants(void) { /* Expected hashes of all points in the tests below. Computed using an * independent implementation. */ static const unsigned char expected32_6bit20[32] = { @@ -5340,7 +5338,7 @@ void run_ecmult_constants(void) { } } -void test_ecmult_gen_blind(void) { +static void test_ecmult_gen_blind(void) { /* Test ecmult_gen() blinding and confirm that the blinding changes, the affine points match, and the z's don't match. */ secp256k1_scalar key; secp256k1_scalar b; @@ -5363,7 +5361,7 @@ void test_ecmult_gen_blind(void) { ge_equals_gej(&pge, &pgej2); } -void test_ecmult_gen_blind_reset(void) { +static void test_ecmult_gen_blind_reset(void) { /* Test ecmult_gen() blinding reset and confirm that the blinding is consistent. */ secp256k1_scalar b; secp256k1_gej initial; @@ -5375,7 +5373,7 @@ void test_ecmult_gen_blind_reset(void) { CHECK(gej_xyz_equals_gej(&initial, &ctx->ecmult_gen_ctx.initial)); } -void run_ecmult_gen_blind(void) { +static void run_ecmult_gen_blind(void) { int i; test_ecmult_gen_blind_reset(); for (i = 0; i < 10; i++) { @@ -5384,7 +5382,7 @@ void run_ecmult_gen_blind(void) { } /***** ENDOMORPHISH TESTS *****/ -void test_scalar_split(const secp256k1_scalar* full) { +static void test_scalar_split(const secp256k1_scalar* full) { secp256k1_scalar s, s1, slam; const unsigned char zero[32] = {0}; unsigned char tmp[32]; @@ -5411,7 +5409,7 @@ void test_scalar_split(const secp256k1_scalar* full) { } -void run_endomorphism_tests(void) { +static void run_endomorphism_tests(void) { unsigned i; static secp256k1_scalar s; test_scalar_split(&secp256k1_scalar_zero); @@ -5432,7 +5430,7 @@ void run_endomorphism_tests(void) { } } -void ec_pubkey_parse_pointtest(const unsigned char *input, int xvalid, int yvalid) { +static void ec_pubkey_parse_pointtest(const unsigned char *input, int xvalid, int yvalid) { unsigned char pubkeyc[65]; secp256k1_pubkey pubkey; secp256k1_ge ge; @@ -5507,7 +5505,7 @@ void ec_pubkey_parse_pointtest(const unsigned char *input, int xvalid, int yvali secp256k1_context_set_illegal_callback(ctx, NULL, NULL); } -void run_ec_pubkey_parse_test(void) { +static void run_ec_pubkey_parse_test(void) { #define SECP256K1_EC_PARSE_TEST_NVALID (12) const unsigned char valid[SECP256K1_EC_PARSE_TEST_NVALID][64] = { { @@ -5835,7 +5833,7 @@ void run_ec_pubkey_parse_test(void) { } } -void run_eckey_edge_case_test(void) { +static void run_eckey_edge_case_test(void) { const unsigned char orderc[32] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, @@ -6091,7 +6089,7 @@ void run_eckey_edge_case_test(void) { secp256k1_context_set_illegal_callback(ctx, NULL, NULL); } -void run_eckey_negate_test(void) { +static void run_eckey_negate_test(void) { unsigned char seckey[32]; unsigned char seckey_tmp[32]; @@ -6126,14 +6124,14 @@ void run_eckey_negate_test(void) { CHECK(secp256k1_memcmp_var(seckey, seckey_tmp, 32) == 0); } -void random_sign(secp256k1_scalar *sigr, secp256k1_scalar *sigs, const secp256k1_scalar *key, const secp256k1_scalar *msg, int *recid) { +static void random_sign(secp256k1_scalar *sigr, secp256k1_scalar *sigs, const secp256k1_scalar *key, const secp256k1_scalar *msg, int *recid) { secp256k1_scalar nonce; do { random_scalar_order_test(&nonce); } while(!secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, sigr, sigs, key, msg, &nonce, recid)); } -void test_ecdsa_sign_verify(void) { +static void test_ecdsa_sign_verify(void) { secp256k1_gej pubj; secp256k1_ge pub; secp256k1_scalar one; @@ -6160,7 +6158,7 @@ void test_ecdsa_sign_verify(void) { CHECK(!secp256k1_ecdsa_sig_verify(&sigr, &sigs, &pub, &msg)); } -void run_ecdsa_sign_verify(void) { +static void run_ecdsa_sign_verify(void) { int i; for (i = 0; i < 10*count; i++) { test_ecdsa_sign_verify(); @@ -6214,12 +6212,12 @@ static int nonce_function_test_retry(unsigned char *nonce32, const unsigned char return nonce_function_rfc6979(nonce32, msg32, key32, algo16, data, counter - 5); } -int is_empty_signature(const secp256k1_ecdsa_signature *sig) { +static int is_empty_signature(const secp256k1_ecdsa_signature *sig) { static const unsigned char res[sizeof(secp256k1_ecdsa_signature)] = {0}; return secp256k1_memcmp_var(sig, res, sizeof(secp256k1_ecdsa_signature)) == 0; } -void test_ecdsa_end_to_end(void) { +static void test_ecdsa_end_to_end(void) { unsigned char extra[32] = {0x00}; unsigned char privkey[32]; unsigned char message[32]; @@ -6364,7 +6362,7 @@ void test_ecdsa_end_to_end(void) { secp256k1_ecdsa_verify(ctx, &signature[0], message, &pubkey) == 0); } -void test_random_pubkeys(void) { +static void test_random_pubkeys(void) { secp256k1_ge elem; secp256k1_ge elem2; unsigned char in[65]; @@ -6424,7 +6422,7 @@ void test_random_pubkeys(void) { } } -void run_pubkey_comparison(void) { +static void run_pubkey_comparison(void) { unsigned char pk1_ser[33] = { 0x02, 0x58, 0x84, 0xb3, 0xa2, 0x4b, 0x97, 0x37, 0x88, 0x92, 0x38, 0xa6, 0x26, 0x62, 0x52, 0x35, 0x11, @@ -6473,21 +6471,21 @@ void run_pubkey_comparison(void) { CHECK(secp256k1_ec_pubkey_cmp(ctx, &pk2, &pk1) > 0); } -void run_random_pubkeys(void) { +static void run_random_pubkeys(void) { int i; for (i = 0; i < 10*count; i++) { test_random_pubkeys(); } } -void run_ecdsa_end_to_end(void) { +static void run_ecdsa_end_to_end(void) { int i; for (i = 0; i < 64*count; i++) { test_ecdsa_end_to_end(); } } -int test_ecdsa_der_parse(const unsigned char *sig, size_t siglen, int certainly_der, int certainly_not_der) { +static int test_ecdsa_der_parse(const unsigned char *sig, size_t siglen, int certainly_der, int certainly_not_der) { static const unsigned char zeroes[32] = {0}; int ret = 0; @@ -6732,7 +6730,7 @@ static void random_ber_signature(unsigned char *sig, size_t *len, int* certainly CHECK(tlen == *len); } -void run_ecdsa_der_parse(void) { +static void run_ecdsa_der_parse(void) { int i,j; for (i = 0; i < 200 * count; i++) { unsigned char buffer[2048]; @@ -6764,7 +6762,7 @@ void run_ecdsa_der_parse(void) { } /* Tests several edge cases. */ -void test_ecdsa_edge_cases(void) { +static void test_ecdsa_edge_cases(void) { int t; secp256k1_ecdsa_signature sig; @@ -7133,7 +7131,7 @@ void test_ecdsa_edge_cases(void) { } } -void run_ecdsa_edge_cases(void) { +static void run_ecdsa_edge_cases(void) { test_ecdsa_edge_cases(); } @@ -7153,7 +7151,7 @@ void run_ecdsa_edge_cases(void) { # include "modules/schnorrsig/tests_impl.h" #endif -void run_secp256k1_memczero_test(void) { +static void run_secp256k1_memczero_test(void) { unsigned char buf1[6] = {1, 2, 3, 4, 5, 6}; unsigned char buf2[sizeof(buf1)]; @@ -7168,7 +7166,7 @@ void run_secp256k1_memczero_test(void) { CHECK(secp256k1_memcmp_var(buf1, buf2, sizeof(buf1)) == 0); } -void run_secp256k1_byteorder_tests(void) { +static void run_secp256k1_byteorder_tests(void) { const uint32_t x = 0xFF03AB45; const unsigned char x_be[4] = {0xFF, 0x03, 0xAB, 0x45}; unsigned char buf[4]; @@ -7181,7 +7179,7 @@ void run_secp256k1_byteorder_tests(void) { CHECK(x == x_); } -void int_cmov_test(void) { +static void int_cmov_test(void) { int r = INT_MAX; int a = 0; @@ -7206,7 +7204,7 @@ void int_cmov_test(void) { } -void fe_cmov_test(void) { +static void fe_cmov_test(void) { static const secp256k1_fe zero = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0); static const secp256k1_fe one = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1); static const secp256k1_fe max = SECP256K1_FE_CONST( @@ -7236,7 +7234,7 @@ void fe_cmov_test(void) { CHECK(secp256k1_memcmp_var(&r, &one, sizeof(r)) == 0); } -void fe_storage_cmov_test(void) { +static void fe_storage_cmov_test(void) { static const secp256k1_fe_storage zero = SECP256K1_FE_STORAGE_CONST(0, 0, 0, 0, 0, 0, 0, 0); static const secp256k1_fe_storage one = SECP256K1_FE_STORAGE_CONST(0, 0, 0, 0, 0, 0, 0, 1); static const secp256k1_fe_storage max = SECP256K1_FE_STORAGE_CONST( @@ -7266,7 +7264,7 @@ void fe_storage_cmov_test(void) { CHECK(secp256k1_memcmp_var(&r, &one, sizeof(r)) == 0); } -void scalar_cmov_test(void) { +static void scalar_cmov_test(void) { static const secp256k1_scalar zero = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); static const secp256k1_scalar one = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1); static const secp256k1_scalar max = SECP256K1_SCALAR_CONST( @@ -7296,7 +7294,7 @@ void scalar_cmov_test(void) { CHECK(secp256k1_memcmp_var(&r, &one, sizeof(r)) == 0); } -void ge_storage_cmov_test(void) { +static void ge_storage_cmov_test(void) { static const secp256k1_ge_storage zero = SECP256K1_GE_STORAGE_CONST(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); static const secp256k1_ge_storage one = SECP256K1_GE_STORAGE_CONST(0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1); static const secp256k1_ge_storage max = SECP256K1_GE_STORAGE_CONST( @@ -7328,7 +7326,7 @@ void ge_storage_cmov_test(void) { CHECK(secp256k1_memcmp_var(&r, &one, sizeof(r)) == 0); } -void run_cmov_tests(void) { +static void run_cmov_tests(void) { int_cmov_test(); fe_cmov_test(); fe_storage_cmov_test(); diff --git a/src/tests_exhaustive.c b/src/tests_exhaustive.c index 7eccd77f..86b9334c 100644 --- a/src/tests_exhaustive.c +++ b/src/tests_exhaustive.c @@ -24,7 +24,7 @@ static int count = 2; /** stolen from tests.c */ -void ge_equals_ge(const secp256k1_ge *a, const secp256k1_ge *b) { +static void ge_equals_ge(const secp256k1_ge *a, const secp256k1_ge *b) { CHECK(a->infinity == b->infinity); if (a->infinity) { return; @@ -33,7 +33,7 @@ void ge_equals_ge(const secp256k1_ge *a, const secp256k1_ge *b) { CHECK(secp256k1_fe_equal_var(&a->y, &b->y)); } -void ge_equals_gej(const secp256k1_ge *a, const secp256k1_gej *b) { +static void ge_equals_gej(const secp256k1_ge *a, const secp256k1_gej *b) { secp256k1_fe z2s; secp256k1_fe u1, u2, s1, s2; CHECK(a->infinity == b->infinity); @@ -50,7 +50,7 @@ void ge_equals_gej(const secp256k1_ge *a, const secp256k1_gej *b) { CHECK(secp256k1_fe_equal_var(&s1, &s2)); } -void random_fe(secp256k1_fe *x) { +static void random_fe(secp256k1_fe *x) { unsigned char bin[32]; do { secp256k1_testrand256(bin); @@ -70,7 +70,7 @@ SECP256K1_INLINE static int skip_section(uint64_t* iter) { return ((((uint32_t)*iter ^ (*iter >> 32)) * num_cores) >> 32) != this_core; } -int secp256k1_nonce_function_smallint(unsigned char *nonce32, const unsigned char *msg32, +static int secp256k1_nonce_function_smallint(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int attempt) { secp256k1_scalar s; @@ -90,7 +90,7 @@ int secp256k1_nonce_function_smallint(unsigned char *nonce32, const unsigned cha return 1; } -void test_exhaustive_endomorphism(const secp256k1_ge *group) { +static void test_exhaustive_endomorphism(const secp256k1_ge *group) { int i; for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++) { secp256k1_ge res; @@ -99,7 +99,7 @@ void test_exhaustive_endomorphism(const secp256k1_ge *group) { } } -void test_exhaustive_addition(const secp256k1_ge *group, const secp256k1_gej *groupj) { +static void test_exhaustive_addition(const secp256k1_ge *group, const secp256k1_gej *groupj) { int i, j; uint64_t iter = 0; @@ -159,7 +159,7 @@ void test_exhaustive_addition(const secp256k1_ge *group, const secp256k1_gej *gr } } -void test_exhaustive_ecmult(const secp256k1_ge *group, const secp256k1_gej *groupj) { +static void test_exhaustive_ecmult(const secp256k1_ge *group, const secp256k1_gej *groupj) { int i, j, r_log; uint64_t iter = 0; for (r_log = 1; r_log < EXHAUSTIVE_TEST_ORDER; r_log++) { @@ -195,7 +195,7 @@ static int ecmult_multi_callback(secp256k1_scalar *sc, secp256k1_ge *pt, size_t return 1; } -void test_exhaustive_ecmult_multi(const secp256k1_context *ctx, const secp256k1_ge *group) { +static void test_exhaustive_ecmult_multi(const secp256k1_context *ctx, const secp256k1_ge *group) { int i, j, k, x, y; uint64_t iter = 0; secp256k1_scratch *scratch = secp256k1_scratch_create(&ctx->error_callback, 4096); @@ -225,7 +225,7 @@ void test_exhaustive_ecmult_multi(const secp256k1_context *ctx, const secp256k1_ secp256k1_scratch_destroy(&ctx->error_callback, scratch); } -void r_from_k(secp256k1_scalar *r, const secp256k1_ge *group, int k, int* overflow) { +static void r_from_k(secp256k1_scalar *r, const secp256k1_ge *group, int k, int* overflow) { secp256k1_fe x; unsigned char x_bin[32]; k %= EXHAUSTIVE_TEST_ORDER; @@ -235,7 +235,7 @@ void r_from_k(secp256k1_scalar *r, const secp256k1_ge *group, int k, int* overfl secp256k1_scalar_set_b32(r, x_bin, overflow); } -void test_exhaustive_verify(const secp256k1_context *ctx, const secp256k1_ge *group) { +static void test_exhaustive_verify(const secp256k1_context *ctx, const secp256k1_ge *group) { int s, r, msg, key; uint64_t iter = 0; for (s = 1; s < EXHAUSTIVE_TEST_ORDER; s++) { @@ -288,7 +288,7 @@ void test_exhaustive_verify(const secp256k1_context *ctx, const secp256k1_ge *gr } } -void test_exhaustive_sign(const secp256k1_context *ctx, const secp256k1_ge *group) { +static void test_exhaustive_sign(const secp256k1_context *ctx, const secp256k1_ge *group) { int i, j, k; uint64_t iter = 0; diff --git a/src/valgrind_ctime_test.c b/src/valgrind_ctime_test.c index a0f888b0..fcc28de2 100644 --- a/src/valgrind_ctime_test.c +++ b/src/valgrind_ctime_test.c @@ -27,7 +27,7 @@ #include "../include/secp256k1_schnorrsig.h" #endif -void run_tests(secp256k1_context *ctx, unsigned char *key); +static void run_tests(secp256k1_context *ctx, unsigned char *key); int main(void) { secp256k1_context* ctx; @@ -60,7 +60,7 @@ int main(void) { return 0; } -void run_tests(secp256k1_context *ctx, unsigned char *key) { +static void run_tests(secp256k1_context *ctx, unsigned char *key) { secp256k1_ecdsa_signature signature; secp256k1_pubkey pubkey; size_t siglen = 74; From 4f1a54e41d84a81e4506668bfabed1f3c632973b Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Tue, 6 Dec 2022 23:35:30 -0500 Subject: [PATCH 05/47] Move valgrind CPPFLAGS into SECP_CONFIG_DEFINES --- Makefile.am | 6 +----- configure.ac | 2 +- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/Makefile.am b/Makefile.am index 666afa5d..d0258480 100644 --- a/Makefile.am +++ b/Makefile.am @@ -96,10 +96,6 @@ libsecp256k1_la_CPPFLAGS = $(SECP_INCLUDES) $(SECP_CONFIG_DEFINES) libsecp256k1_la_LIBADD = $(SECP_LIBS) $(COMMON_LIB) $(PRECOMPUTED_LIB) libsecp256k1_la_LDFLAGS = -no-undefined -version-info $(LIB_VERSION_CURRENT):$(LIB_VERSION_REVISION):$(LIB_VERSION_AGE) -if VALGRIND_ENABLED -libsecp256k1_la_CPPFLAGS += -DVALGRIND -endif - noinst_PROGRAMS = if USE_BENCHMARK noinst_PROGRAMS += bench bench_internal bench_ecmult @@ -123,10 +119,10 @@ noverify_tests_CPPFLAGS = $(SECP_INCLUDES) $(SECP_TEST_INCLUDES) $(SECP_CONFIG_D noverify_tests_LDADD = $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB) $(PRECOMPUTED_LIB) noverify_tests_LDFLAGS = -static if VALGRIND_ENABLED -noverify_tests_CPPFLAGS += -DVALGRIND noinst_PROGRAMS += valgrind_ctime_test valgrind_ctime_test_SOURCES = src/valgrind_ctime_test.c valgrind_ctime_test_LDADD = libsecp256k1.la $(SECP_LIBS) $(COMMON_LIB) +valgrind_ctime_test_CPPFLAGS = $(SECP_CONFIG_DEFINES) endif if !ENABLE_COVERAGE TESTS += tests diff --git a/configure.ac b/configure.ac index d389a108..88b0ee58 100644 --- a/configure.ac +++ b/configure.ac @@ -344,7 +344,7 @@ case $set_ecmult_gen_precision in esac if test x"$enable_valgrind" = x"yes"; then - SECP_INCLUDES="$SECP_INCLUDES $VALGRIND_CPPFLAGS" + SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES $VALGRIND_CPPFLAGS -DVALGRIND" fi # Add -Werror and similar flags passed from the outside (for testing, e.g., in CI). From 0db05a770ebd41999b88358ee6ab4bdd6a7d57ee Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Tue, 6 Dec 2022 16:35:35 -0500 Subject: [PATCH 06/47] Abstract interactions with valgrind behind new checkmem.h --- Makefile.am | 1 + src/checkmem.h | 74 ++++++++++++++++++ src/field_10x26_impl.h | 5 +- src/field_5x52_impl.h | 5 +- src/scalar_4x64_impl.h | 3 +- src/scalar_8x32_impl.h | 3 +- src/scalar_low_impl.h | 3 +- src/secp256k1.c | 16 +--- src/tests.c | 155 +++++++++++++++++++------------------- src/util.h | 19 ----- src/valgrind_ctime_test.c | 71 +++++++++-------- 11 files changed, 203 insertions(+), 152 deletions(-) create mode 100644 src/checkmem.h diff --git a/Makefile.am b/Makefile.am index d0258480..b5925235 100644 --- a/Makefile.am +++ b/Makefile.am @@ -47,6 +47,7 @@ noinst_HEADERS += src/modinv64_impl.h noinst_HEADERS += src/precomputed_ecmult.h noinst_HEADERS += src/precomputed_ecmult_gen.h noinst_HEADERS += src/assumptions.h +noinst_HEADERS += src/checkmem.h noinst_HEADERS += src/util.h noinst_HEADERS += src/int128.h noinst_HEADERS += src/int128_impl.h diff --git a/src/checkmem.h b/src/checkmem.h new file mode 100644 index 00000000..55d96c3d --- /dev/null +++ b/src/checkmem.h @@ -0,0 +1,74 @@ +/*********************************************************************** + * Copyright (c) 2022 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +/* The code here is inspired by Kris Kwiatkowski's approach in + * https://github.com/kriskwiatkowski/pqc/blob/main/src/common/ct_check.h + * to provide a general interface for memory-checking mechanisms, primarily + * for constant-time checking. + */ + +/* These macros are defined by this header file: + * + * - SECP256K1_CHECKMEM_ENABLED: + * - 1 if memory-checking integration is available, 0 otherwise. + * This is just a compile-time macro. Use the next macro to check it is actually + * available at runtime. + * - SECP256K1_CHECKMEM_RUNNING(): + * - Acts like a function call, returning 1 if memory checking is available + * at runtime. + * - SECP256K1_CHECKMEM_CHECK(p, len): + * - Assert or otherwise fail in case the len-byte memory block pointed to by p is + * not considered entirely defined. + * - SECP256K1_CHECKMEM_CHECK_VERIFY(p, len): + * - Like SECP256K1_CHECKMEM_CHECK, but only works in VERIFY mode. + * - SECP256K1_CHECKMEM_UNDEFINE(p, len): + * - marks the len-byte memory block pointed to by p as undefined data (secret data, + * in the context of constant-time checking). + * - SECP256K1_CHECKMEM_DEFINE(p, len): + * - marks the len-byte memory pointed to by p as defined data (public data, in the + * context of constant-time checking). + * + */ + +#ifndef SECP256K1_CHECKMEM_H +#define SECP256K1_CHECKMEM_H + +/* Define a statement-like macro that ignores the arguments. */ +#define SECP256K1_CHECKMEM_NOOP(p, len) do { (void)(p); (void)(len); } while(0) + +/* If valgrind integration is desired (through the VALGRIND define), implement the + * SECP256K1_CHECKMEM_* macros using valgrind. */ +#if !defined SECP256K1_CHECKMEM_ENABLED +# if defined VALGRIND +# include +# include +# define SECP256K1_CHECKMEM_ENABLED 1 +# define SECP256K1_CHECKMEM_UNDEFINE(p, len) VALGRIND_MAKE_MEM_UNDEFINED((p), (len)) +# define SECP256K1_CHECKMEM_DEFINE(p, len) VALGRIND_MAKE_MEM_DEFINED((p), (len)) +# define SECP256K1_CHECKMEM_CHECK(p, len) VALGRIND_CHECK_MEM_IS_DEFINED((p), (len)) + /* VALGRIND_MAKE_MEM_DEFINED returns 0 iff not running on memcheck. + * This is more precise than the RUNNING_ON_VALGRIND macro, which + * checks for valgrind in general instead of memcheck specifically. */ +# define SECP256K1_CHECKMEM_RUNNING() (VALGRIND_MAKE_MEM_DEFINED(NULL, 0) != 0) +# endif +#endif + +/* As a fall-back, map these macros to dummy statements. */ +#if !defined SECP256K1_CHECKMEM_ENABLED +# define SECP256K1_CHECKMEM_ENABLED 0 +# define SECP256K1_CHECKMEM_UNDEFINE(p, len) SECP256K1_CHECKMEM_NOOP((p), (len)) +# define SECP256K1_CHECKMEM_DEFINE(p, len) SECP256K1_CHECKMEM_NOOP((p), (len)) +# define SECP256K1_CHECKMEM_CHECK(p, len) SECP256K1_CHECKMEM_NOOP((p), (len)) +# define SECP256K1_CHECKMEM_RUNNING() (0) +#endif + +#if defined VERIFY +#define SECP256K1_CHECKMEM_CHECK_VERIFY(p, len) SECP256K1_CHECKMEM_CHECK((p), (len)) +#else +#define SECP256K1_CHECKMEM_CHECK_VERIFY(p, len) SECP256K1_CHECKMEM_NOOP((p), (len)) +#endif + +#endif /* SECP256K1_CHECKMEM_H */ diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h index 21742bf6..5e6c63cf 100644 --- a/src/field_10x26_impl.h +++ b/src/field_10x26_impl.h @@ -7,6 +7,7 @@ #ifndef SECP256K1_FIELD_REPR_IMPL_H #define SECP256K1_FIELD_REPR_IMPL_H +#include "checkmem.h" #include "util.h" #include "field.h" #include "modinv32_impl.h" @@ -1132,7 +1133,7 @@ static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a) { static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) { uint32_t mask0, mask1; - VG_CHECK_VERIFY(r->n, sizeof(r->n)); + SECP256K1_CHECKMEM_CHECK_VERIFY(r->n, sizeof(r->n)); mask0 = flag + ~((uint32_t)0); mask1 = ~mask0; r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1); @@ -1231,7 +1232,7 @@ static SECP256K1_INLINE void secp256k1_fe_half(secp256k1_fe *r) { static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag) { uint32_t mask0, mask1; - VG_CHECK_VERIFY(r->n, sizeof(r->n)); + SECP256K1_CHECKMEM_CHECK_VERIFY(r->n, sizeof(r->n)); mask0 = flag + ~((uint32_t)0); mask1 = ~mask0; r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1); diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h index 63487ef5..985c486a 100644 --- a/src/field_5x52_impl.h +++ b/src/field_5x52_impl.h @@ -7,6 +7,7 @@ #ifndef SECP256K1_FIELD_REPR_IMPL_H #define SECP256K1_FIELD_REPR_IMPL_H +#include "checkmem.h" #include "util.h" #include "field.h" #include "modinv64_impl.h" @@ -472,7 +473,7 @@ static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a) { static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) { uint64_t mask0, mask1; - VG_CHECK_VERIFY(r->n, sizeof(r->n)); + SECP256K1_CHECKMEM_CHECK_VERIFY(r->n, sizeof(r->n)); mask0 = flag + ~((uint64_t)0); mask1 = ~mask0; r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1); @@ -555,7 +556,7 @@ static SECP256K1_INLINE void secp256k1_fe_half(secp256k1_fe *r) { static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag) { uint64_t mask0, mask1; - VG_CHECK_VERIFY(r->n, sizeof(r->n)); + SECP256K1_CHECKMEM_CHECK_VERIFY(r->n, sizeof(r->n)); mask0 = flag + ~((uint64_t)0); mask1 = ~mask0; r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1); diff --git a/src/scalar_4x64_impl.h b/src/scalar_4x64_impl.h index 4588219d..1b83575b 100644 --- a/src/scalar_4x64_impl.h +++ b/src/scalar_4x64_impl.h @@ -7,6 +7,7 @@ #ifndef SECP256K1_SCALAR_REPR_IMPL_H #define SECP256K1_SCALAR_REPR_IMPL_H +#include "checkmem.h" #include "int128.h" #include "modinv64_impl.h" @@ -810,7 +811,7 @@ SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r, static SECP256K1_INLINE void secp256k1_scalar_cmov(secp256k1_scalar *r, const secp256k1_scalar *a, int flag) { uint64_t mask0, mask1; - VG_CHECK_VERIFY(r->d, sizeof(r->d)); + SECP256K1_CHECKMEM_CHECK_VERIFY(r->d, sizeof(r->d)); mask0 = flag + ~((uint64_t)0); mask1 = ~mask0; r->d[0] = (r->d[0] & mask0) | (a->d[0] & mask1); diff --git a/src/scalar_8x32_impl.h b/src/scalar_8x32_impl.h index 62c7ae71..c433adce 100644 --- a/src/scalar_8x32_impl.h +++ b/src/scalar_8x32_impl.h @@ -7,6 +7,7 @@ #ifndef SECP256K1_SCALAR_REPR_IMPL_H #define SECP256K1_SCALAR_REPR_IMPL_H +#include "checkmem.h" #include "modinv32_impl.h" /* Limbs of the secp256k1 order. */ @@ -631,7 +632,7 @@ SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r, static SECP256K1_INLINE void secp256k1_scalar_cmov(secp256k1_scalar *r, const secp256k1_scalar *a, int flag) { uint32_t mask0, mask1; - VG_CHECK_VERIFY(r->d, sizeof(r->d)); + SECP256K1_CHECKMEM_CHECK_VERIFY(r->d, sizeof(r->d)); mask0 = flag + ~((uint32_t)0); mask1 = ~mask0; r->d[0] = (r->d[0] & mask0) | (a->d[0] & mask1); diff --git a/src/scalar_low_impl.h b/src/scalar_low_impl.h index 7176f0b2..e7800833 100644 --- a/src/scalar_low_impl.h +++ b/src/scalar_low_impl.h @@ -7,6 +7,7 @@ #ifndef SECP256K1_SCALAR_REPR_IMPL_H #define SECP256K1_SCALAR_REPR_IMPL_H +#include "checkmem.h" #include "scalar.h" #include @@ -115,7 +116,7 @@ SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar *a, const static SECP256K1_INLINE void secp256k1_scalar_cmov(secp256k1_scalar *r, const secp256k1_scalar *a, int flag) { uint32_t mask0, mask1; - VG_CHECK_VERIFY(r, sizeof(*r)); + SECP256K1_CHECKMEM_CHECK_VERIFY(r, sizeof(*r)); mask0 = flag + ~((uint32_t)0); mask1 = ~mask0; *r = (*r & mask0) | (*a & mask1); diff --git a/src/secp256k1.c b/src/secp256k1.c index 67c8019d..89bb0af8 100644 --- a/src/secp256k1.c +++ b/src/secp256k1.c @@ -21,6 +21,7 @@ #include "../include/secp256k1_preallocated.h" #include "assumptions.h" +#include "checkmem.h" #include "util.h" #include "field_impl.h" @@ -40,10 +41,6 @@ # error "secp256k1.h processed without SECP256K1_BUILD defined while building secp256k1.c" #endif -#if defined(VALGRIND) -# include -#endif - #define ARG_CHECK(cond) do { \ if (EXPECT(!(cond), 0)) { \ secp256k1_callback_call(&ctx->illegal_callback, #cond); \ @@ -215,17 +212,10 @@ void secp256k1_scratch_space_destroy(const secp256k1_context *ctx, secp256k1_scr } /* Mark memory as no-longer-secret for the purpose of analysing constant-time behaviour - * of the software. This is setup for use with valgrind but could be substituted with - * the appropriate instrumentation for other analysis tools. + * of the software. */ static SECP256K1_INLINE void secp256k1_declassify(const secp256k1_context* ctx, const void *p, size_t len) { -#if defined(VALGRIND) - if (EXPECT(ctx->declassify,0)) VALGRIND_MAKE_MEM_DEFINED(p, len); -#else - (void)ctx; - (void)p; - (void)len; -#endif + if (EXPECT(ctx->declassify, 0)) SECP256K1_CHECKMEM_DEFINE(p, len); } static int secp256k1_pubkey_load(const secp256k1_context* ctx, secp256k1_ge* ge, const secp256k1_pubkey* pubkey) { diff --git a/src/tests.c b/src/tests.c index 8a1c6f8c..bfdb68d1 100644 --- a/src/tests.c +++ b/src/tests.c @@ -14,6 +14,7 @@ #include "../include/secp256k1.h" #include "../include/secp256k1_preallocated.h" #include "testrand_impl.h" +#include "checkmem.h" #include "util.h" #include "../contrib/lax_der_parsing.c" @@ -193,14 +194,14 @@ void run_ec_illegal_argument_tests(void) { /* Verify context-type checking illegal-argument errors. */ CHECK(secp256k1_ec_pubkey_create(STATIC_CTX, &pubkey, ctmp) == 0); CHECK(ecount == 1); - VG_UNDEF(&pubkey, sizeof(pubkey)); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, ctmp) == 1); - VG_CHECK(&pubkey, sizeof(pubkey)); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); CHECK(secp256k1_ecdsa_sign(STATIC_CTX, &sig, ctmp, ctmp, NULL, NULL) == 0); CHECK(ecount == 2); - VG_UNDEF(&sig, sizeof(sig)); + SECP256K1_CHECKMEM_UNDEFINE(&sig, sizeof(sig)); CHECK(secp256k1_ecdsa_sign(CTX, &sig, ctmp, ctmp, NULL, NULL) == 1); - VG_CHECK(&sig, sizeof(sig)); + SECP256K1_CHECKMEM_CHECK(&sig, sizeof(sig)); CHECK(ecount2 == 10); CHECK(secp256k1_ecdsa_verify(CTX, &sig, ctmp, &pubkey) == 1); CHECK(ecount2 == 10); @@ -5444,7 +5445,7 @@ void ec_pubkey_parse_pointtest(const unsigned char *input, int xvalid, int yvali /* Smaller sizes are tested exhaustively elsewhere. */ int32_t i; memcpy(&pubkeyc[1], input, 64); - VG_UNDEF(&pubkeyc[pubkeyclen], 65 - pubkeyclen); + SECP256K1_CHECKMEM_UNDEFINE(&pubkeyc[pubkeyclen], 65 - pubkeyclen); for (i = 0; i < 256; i++) { /* Try all type bytes. */ int xpass; @@ -5463,14 +5464,14 @@ void ec_pubkey_parse_pointtest(const unsigned char *input, int xvalid, int yvali unsigned char pubkeyo[65]; size_t outl; memset(&pubkey, 0, sizeof(pubkey)); - VG_UNDEF(&pubkey, sizeof(pubkey)); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); ecount = 0; CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, pubkeyc, pubkeyclen) == 1); - VG_CHECK(&pubkey, sizeof(pubkey)); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); outl = 65; - VG_UNDEF(pubkeyo, 65); + SECP256K1_CHECKMEM_UNDEFINE(pubkeyo, 65); CHECK(secp256k1_ec_pubkey_serialize(CTX, pubkeyo, &outl, &pubkey, SECP256K1_EC_COMPRESSED) == 1); - VG_CHECK(pubkeyo, outl); + SECP256K1_CHECKMEM_CHECK(pubkeyo, outl); CHECK(outl == 33); CHECK(secp256k1_memcmp_var(&pubkeyo[1], &pubkeyc[1], 32) == 0); CHECK((pubkeyclen != 33) || (pubkeyo[0] == pubkeyc[0])); @@ -5479,13 +5480,13 @@ void ec_pubkey_parse_pointtest(const unsigned char *input, int xvalid, int yvali CHECK(pubkeyo[0] == ysign); CHECK(secp256k1_pubkey_load(CTX, &ge, &pubkey) == 1); memset(&pubkey, 0, sizeof(pubkey)); - VG_UNDEF(&pubkey, sizeof(pubkey)); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); secp256k1_pubkey_save(&pubkey, &ge); - VG_CHECK(&pubkey, sizeof(pubkey)); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); outl = 65; - VG_UNDEF(pubkeyo, 65); + SECP256K1_CHECKMEM_UNDEFINE(pubkeyo, 65); CHECK(secp256k1_ec_pubkey_serialize(CTX, pubkeyo, &outl, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 1); - VG_CHECK(pubkeyo, outl); + SECP256K1_CHECKMEM_CHECK(pubkeyo, outl); CHECK(outl == 65); CHECK(pubkeyo[0] == 4); CHECK(secp256k1_memcmp_var(&pubkeyo[1], input, 64) == 0); @@ -5495,9 +5496,9 @@ void ec_pubkey_parse_pointtest(const unsigned char *input, int xvalid, int yvali /* These cases must fail to parse. */ memset(&pubkey, 0xfe, sizeof(pubkey)); ecount = 0; - VG_UNDEF(&pubkey, sizeof(pubkey)); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, pubkeyc, pubkeyclen) == 0); - VG_CHECK(&pubkey, sizeof(pubkey)); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); CHECK(ecount == 0); CHECK(secp256k1_pubkey_load(CTX, &ge, &pubkey) == 0); CHECK(ecount == 1); @@ -5696,15 +5697,15 @@ void run_ec_pubkey_parse_test(void) { int32_t ecount2; ecount = 0; /* Nothing should be reading this far into pubkeyc. */ - VG_UNDEF(&pubkeyc[65], 1); + SECP256K1_CHECKMEM_UNDEFINE(&pubkeyc[65], 1); secp256k1_context_set_illegal_callback(CTX, counting_illegal_callback_fn, &ecount); /* Zero length claimed, fail, zeroize, no illegal arg error. */ memset(&pubkey, 0xfe, sizeof(pubkey)); ecount = 0; - VG_UNDEF(shortkey, 2); - VG_UNDEF(&pubkey, sizeof(pubkey)); + SECP256K1_CHECKMEM_UNDEFINE(shortkey, 2); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, shortkey, 0) == 0); - VG_CHECK(&pubkey, sizeof(pubkey)); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); CHECK(ecount == 0); CHECK(secp256k1_pubkey_load(CTX, &ge, &pubkey) == 0); CHECK(ecount == 1); @@ -5713,10 +5714,10 @@ void run_ec_pubkey_parse_test(void) { memset(&pubkey, 0xfe, sizeof(pubkey)); ecount = 0; shortkey[0] = i; - VG_UNDEF(&shortkey[1], 1); - VG_UNDEF(&pubkey, sizeof(pubkey)); + SECP256K1_CHECKMEM_UNDEFINE(&shortkey[1], 1); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, shortkey, 1) == 0); - VG_CHECK(&pubkey, sizeof(pubkey)); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); CHECK(ecount == 0); CHECK(secp256k1_pubkey_load(CTX, &ge, &pubkey) == 0); CHECK(ecount == 1); @@ -5727,19 +5728,19 @@ void run_ec_pubkey_parse_test(void) { ecount = 0; shortkey[0] = i & 255; shortkey[1] = i >> 8; - VG_UNDEF(&pubkey, sizeof(pubkey)); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, shortkey, 2) == 0); - VG_CHECK(&pubkey, sizeof(pubkey)); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); CHECK(ecount == 0); CHECK(secp256k1_pubkey_load(CTX, &ge, &pubkey) == 0); CHECK(ecount == 1); } memset(&pubkey, 0xfe, sizeof(pubkey)); ecount = 0; - VG_UNDEF(&pubkey, sizeof(pubkey)); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); /* 33 bytes claimed on otherwise valid input starting with 0x04, fail, zeroize output, no illegal arg error. */ CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, pubkeyc, 33) == 0); - VG_CHECK(&pubkey, sizeof(pubkey)); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); CHECK(ecount == 0); CHECK(secp256k1_pubkey_load(CTX, &ge, &pubkey) == 0); CHECK(ecount == 1); @@ -5749,43 +5750,43 @@ void run_ec_pubkey_parse_test(void) { /* NULL input string. Illegal arg and zeroize output. */ memset(&pubkey, 0xfe, sizeof(pubkey)); ecount = 0; - VG_UNDEF(&pubkey, sizeof(pubkey)); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, NULL, 65) == 0); - VG_CHECK(&pubkey, sizeof(pubkey)); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); CHECK(ecount == 1); CHECK(secp256k1_pubkey_load(CTX, &ge, &pubkey) == 0); CHECK(ecount == 2); /* 64 bytes claimed on input starting with 0x04, fail, zeroize output, no illegal arg error. */ memset(&pubkey, 0xfe, sizeof(pubkey)); ecount = 0; - VG_UNDEF(&pubkey, sizeof(pubkey)); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, pubkeyc, 64) == 0); - VG_CHECK(&pubkey, sizeof(pubkey)); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); CHECK(ecount == 0); CHECK(secp256k1_pubkey_load(CTX, &ge, &pubkey) == 0); CHECK(ecount == 1); /* 66 bytes claimed, fail, zeroize output, no illegal arg error. */ memset(&pubkey, 0xfe, sizeof(pubkey)); ecount = 0; - VG_UNDEF(&pubkey, sizeof(pubkey)); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, pubkeyc, 66) == 0); - VG_CHECK(&pubkey, sizeof(pubkey)); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); CHECK(ecount == 0); CHECK(secp256k1_pubkey_load(CTX, &ge, &pubkey) == 0); CHECK(ecount == 1); /* Valid parse. */ memset(&pubkey, 0, sizeof(pubkey)); ecount = 0; - VG_UNDEF(&pubkey, sizeof(pubkey)); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, pubkeyc, 65) == 1); CHECK(secp256k1_ec_pubkey_parse(secp256k1_context_static, &pubkey, pubkeyc, 65) == 1); - VG_CHECK(&pubkey, sizeof(pubkey)); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); CHECK(ecount == 0); - VG_UNDEF(&ge, sizeof(ge)); + SECP256K1_CHECKMEM_UNDEFINE(&ge, sizeof(ge)); CHECK(secp256k1_pubkey_load(CTX, &ge, &pubkey) == 1); - VG_CHECK(&ge.x, sizeof(ge.x)); - VG_CHECK(&ge.y, sizeof(ge.y)); - VG_CHECK(&ge.infinity, sizeof(ge.infinity)); + SECP256K1_CHECKMEM_CHECK(&ge.x, sizeof(ge.x)); + SECP256K1_CHECKMEM_CHECK(&ge.y, sizeof(ge.y)); + SECP256K1_CHECKMEM_CHECK(&ge.infinity, sizeof(ge.infinity)); ge_equals_ge(&secp256k1_ge_const_g, &ge); CHECK(ecount == 0); /* secp256k1_ec_pubkey_serialize illegal args. */ @@ -5797,9 +5798,9 @@ void run_ec_pubkey_parse_test(void) { CHECK(secp256k1_ec_pubkey_serialize(CTX, sout, NULL, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 0); CHECK(ecount == 2); len = 65; - VG_UNDEF(sout, 65); + SECP256K1_CHECKMEM_UNDEFINE(sout, 65); CHECK(secp256k1_ec_pubkey_serialize(CTX, sout, &len, NULL, SECP256K1_EC_UNCOMPRESSED) == 0); - VG_CHECK(sout, 65); + SECP256K1_CHECKMEM_CHECK(sout, 65); CHECK(ecount == 3); CHECK(len == 0); len = 65; @@ -5807,9 +5808,9 @@ void run_ec_pubkey_parse_test(void) { CHECK(ecount == 4); CHECK(len == 0); len = 65; - VG_UNDEF(sout, 65); + SECP256K1_CHECKMEM_UNDEFINE(sout, 65); CHECK(secp256k1_ec_pubkey_serialize(CTX, sout, &len, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 1); - VG_CHECK(sout, 65); + SECP256K1_CHECKMEM_CHECK(sout, 65); CHECK(ecount == 4); CHECK(len == 65); /* Multiple illegal args. Should still set arg error only once. */ @@ -5854,33 +5855,33 @@ void run_eckey_edge_case_test(void) { int32_t ecount; /* Group order is too large, reject. */ CHECK(secp256k1_ec_seckey_verify(CTX, orderc) == 0); - VG_UNDEF(&pubkey, sizeof(pubkey)); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, orderc) == 0); - VG_CHECK(&pubkey, sizeof(pubkey)); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); /* Maximum value is too large, reject. */ memset(ctmp, 255, 32); CHECK(secp256k1_ec_seckey_verify(CTX, ctmp) == 0); memset(&pubkey, 1, sizeof(pubkey)); - VG_UNDEF(&pubkey, sizeof(pubkey)); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, ctmp) == 0); - VG_CHECK(&pubkey, sizeof(pubkey)); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); /* Zero is too small, reject. */ memset(ctmp, 0, 32); CHECK(secp256k1_ec_seckey_verify(CTX, ctmp) == 0); memset(&pubkey, 1, sizeof(pubkey)); - VG_UNDEF(&pubkey, sizeof(pubkey)); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, ctmp) == 0); - VG_CHECK(&pubkey, sizeof(pubkey)); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); /* One must be accepted. */ ctmp[31] = 0x01; CHECK(secp256k1_ec_seckey_verify(CTX, ctmp) == 1); memset(&pubkey, 0, sizeof(pubkey)); - VG_UNDEF(&pubkey, sizeof(pubkey)); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, ctmp) == 1); - VG_CHECK(&pubkey, sizeof(pubkey)); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); pubkey_one = pubkey; /* Group order + 1 is too large, reject. */ @@ -5888,17 +5889,17 @@ void run_eckey_edge_case_test(void) { ctmp[31] = 0x42; CHECK(secp256k1_ec_seckey_verify(CTX, ctmp) == 0); memset(&pubkey, 1, sizeof(pubkey)); - VG_UNDEF(&pubkey, sizeof(pubkey)); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, ctmp) == 0); - VG_CHECK(&pubkey, sizeof(pubkey)); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); /* -1 must be accepted. */ ctmp[31] = 0x40; CHECK(secp256k1_ec_seckey_verify(CTX, ctmp) == 1); memset(&pubkey, 0, sizeof(pubkey)); - VG_UNDEF(&pubkey, sizeof(pubkey)); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, ctmp) == 1); - VG_CHECK(&pubkey, sizeof(pubkey)); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); pubkey_negone = pubkey; /* Tweak of zero leaves the value unchanged. */ @@ -6030,29 +6031,29 @@ void run_eckey_edge_case_test(void) { /* secp256k1_ec_pubkey_combine tests. */ ecount = 0; pubkeys[0] = &pubkey_one; - VG_UNDEF(&pubkeys[0], sizeof(secp256k1_pubkey *)); - VG_UNDEF(&pubkeys[1], sizeof(secp256k1_pubkey *)); - VG_UNDEF(&pubkeys[2], sizeof(secp256k1_pubkey *)); + SECP256K1_CHECKMEM_UNDEFINE(&pubkeys[0], sizeof(secp256k1_pubkey *)); + SECP256K1_CHECKMEM_UNDEFINE(&pubkeys[1], sizeof(secp256k1_pubkey *)); + SECP256K1_CHECKMEM_UNDEFINE(&pubkeys[2], sizeof(secp256k1_pubkey *)); memset(&pubkey, 255, sizeof(secp256k1_pubkey)); - VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey)); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(secp256k1_pubkey)); CHECK(secp256k1_ec_pubkey_combine(CTX, &pubkey, pubkeys, 0) == 0); - VG_CHECK(&pubkey, sizeof(secp256k1_pubkey)); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(secp256k1_pubkey)); CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); CHECK(ecount == 1); CHECK(secp256k1_ec_pubkey_combine(CTX, NULL, pubkeys, 1) == 0); CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); CHECK(ecount == 2); memset(&pubkey, 255, sizeof(secp256k1_pubkey)); - VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey)); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(secp256k1_pubkey)); CHECK(secp256k1_ec_pubkey_combine(CTX, &pubkey, NULL, 1) == 0); - VG_CHECK(&pubkey, sizeof(secp256k1_pubkey)); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(secp256k1_pubkey)); CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); CHECK(ecount == 3); pubkeys[0] = &pubkey_negone; memset(&pubkey, 255, sizeof(secp256k1_pubkey)); - VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey)); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(secp256k1_pubkey)); CHECK(secp256k1_ec_pubkey_combine(CTX, &pubkey, pubkeys, 1) == 1); - VG_CHECK(&pubkey, sizeof(secp256k1_pubkey)); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(secp256k1_pubkey)); CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); CHECK(ecount == 3); len = 33; @@ -6063,17 +6064,17 @@ void run_eckey_edge_case_test(void) { pubkeys[0] = &pubkey_one; pubkeys[1] = &pubkey_negone; memset(&pubkey, 255, sizeof(secp256k1_pubkey)); - VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey)); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(secp256k1_pubkey)); CHECK(secp256k1_ec_pubkey_combine(CTX, &pubkey, pubkeys, 2) == 0); - VG_CHECK(&pubkey, sizeof(secp256k1_pubkey)); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(secp256k1_pubkey)); CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); CHECK(ecount == 3); /* Passes through infinity but comes out one. */ pubkeys[2] = &pubkey_one; memset(&pubkey, 255, sizeof(secp256k1_pubkey)); - VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey)); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(secp256k1_pubkey)); CHECK(secp256k1_ec_pubkey_combine(CTX, &pubkey, pubkeys, 3) == 1); - VG_CHECK(&pubkey, sizeof(secp256k1_pubkey)); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(secp256k1_pubkey)); CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); CHECK(ecount == 3); len = 33; @@ -6083,9 +6084,9 @@ void run_eckey_edge_case_test(void) { /* Adds to two. */ pubkeys[1] = &pubkey_one; memset(&pubkey, 255, sizeof(secp256k1_pubkey)); - VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey)); + SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(secp256k1_pubkey)); CHECK(secp256k1_ec_pubkey_combine(CTX, &pubkey, pubkeys, 2) == 1); - VG_CHECK(&pubkey, sizeof(secp256k1_pubkey)); + SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(secp256k1_pubkey)); CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); CHECK(ecount == 3); secp256k1_context_set_illegal_callback(CTX, NULL, NULL); @@ -7096,18 +7097,18 @@ void test_ecdsa_edge_cases(void) { unsigned char nonce2[32]; unsigned char nonce3[32]; unsigned char nonce4[32]; - VG_UNDEF(nonce,32); - VG_UNDEF(nonce2,32); - VG_UNDEF(nonce3,32); - VG_UNDEF(nonce4,32); + SECP256K1_CHECKMEM_UNDEFINE(nonce,32); + SECP256K1_CHECKMEM_UNDEFINE(nonce2,32); + SECP256K1_CHECKMEM_UNDEFINE(nonce3,32); + SECP256K1_CHECKMEM_UNDEFINE(nonce4,32); CHECK(nonce_function_rfc6979(nonce, zeros, zeros, NULL, NULL, 0) == 1); - VG_CHECK(nonce,32); + SECP256K1_CHECKMEM_CHECK(nonce,32); CHECK(nonce_function_rfc6979(nonce2, zeros, zeros, zeros, NULL, 0) == 1); - VG_CHECK(nonce2,32); + SECP256K1_CHECKMEM_CHECK(nonce2,32); CHECK(nonce_function_rfc6979(nonce3, zeros, zeros, NULL, (void *)zeros, 0) == 1); - VG_CHECK(nonce3,32); + SECP256K1_CHECKMEM_CHECK(nonce3,32); CHECK(nonce_function_rfc6979(nonce4, zeros, zeros, zeros, (void *)zeros, 0) == 1); - VG_CHECK(nonce4,32); + SECP256K1_CHECKMEM_CHECK(nonce4,32); CHECK(secp256k1_memcmp_var(nonce, nonce2, 32) != 0); CHECK(secp256k1_memcmp_var(nonce, nonce3, 32) != 0); CHECK(secp256k1_memcmp_var(nonce, nonce4, 32) != 0); diff --git a/src/util.h b/src/util.h index e1af5a2d..a25ac873 100644 --- a/src/util.h +++ b/src/util.h @@ -97,25 +97,6 @@ static const secp256k1_callback default_error_callback = { #define VERIFY_SETUP(stmt) #endif -/* Define `VG_UNDEF` and `VG_CHECK` when VALGRIND is defined */ -#if !defined(VG_CHECK) -# if defined(VALGRIND) -# include -# define VG_UNDEF(x,y) VALGRIND_MAKE_MEM_UNDEFINED((x),(y)) -# define VG_CHECK(x,y) VALGRIND_CHECK_MEM_IS_DEFINED((x),(y)) -# else -# define VG_UNDEF(x,y) -# define VG_CHECK(x,y) -# endif -#endif - -/* Like `VG_CHECK` but on VERIFY only */ -#if defined(VERIFY) -#define VG_CHECK_VERIFY(x,y) VG_CHECK((x), (y)) -#else -#define VG_CHECK_VERIFY(x,y) -#endif - static SECP256K1_INLINE void *checked_malloc(const secp256k1_callback* cb, size_t size) { void *ret = malloc(size); if (ret == NULL) { diff --git a/src/valgrind_ctime_test.c b/src/valgrind_ctime_test.c index a0f888b0..2e2b6b14 100644 --- a/src/valgrind_ctime_test.c +++ b/src/valgrind_ctime_test.c @@ -4,12 +4,11 @@ * file COPYING or https://www.opensource.org/licenses/mit-license.php.* ***********************************************************************/ -#include #include #include "../include/secp256k1.h" #include "assumptions.h" -#include "util.h" +#include "checkmem.h" #ifdef ENABLE_MODULE_ECDH # include "../include/secp256k1_ecdh.h" @@ -34,7 +33,7 @@ int main(void) { unsigned char key[32]; int ret, i; - if (!RUNNING_ON_VALGRIND) { + if (!SECP256K1_CHECKMEM_RUNNING()) { fprintf(stderr, "This test can only usefully be run inside valgrind.\n"); fprintf(stderr, "Usage: libtool --mode=execute valgrind ./valgrind_ctime_test\n"); return 1; @@ -51,9 +50,9 @@ int main(void) { /* Test context randomisation. Do this last because it leaves the context * tainted. */ - VALGRIND_MAKE_MEM_UNDEFINED(key, 32); + SECP256K1_CHECKMEM_UNDEFINE(key, 32); ret = secp256k1_context_randomize(ctx, key); - VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret); secp256k1_context_destroy(ctx); @@ -83,89 +82,89 @@ void run_tests(secp256k1_context *ctx, unsigned char *key) { } /* Test keygen. */ - VALGRIND_MAKE_MEM_UNDEFINED(key, 32); + SECP256K1_CHECKMEM_UNDEFINE(key, 32); ret = secp256k1_ec_pubkey_create(ctx, &pubkey, key); - VALGRIND_MAKE_MEM_DEFINED(&pubkey, sizeof(secp256k1_pubkey)); - VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); + SECP256K1_CHECKMEM_DEFINE(&pubkey, sizeof(secp256k1_pubkey)); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret); CHECK(secp256k1_ec_pubkey_serialize(ctx, spubkey, &outputlen, &pubkey, SECP256K1_EC_COMPRESSED) == 1); /* Test signing. */ - VALGRIND_MAKE_MEM_UNDEFINED(key, 32); + SECP256K1_CHECKMEM_UNDEFINE(key, 32); ret = secp256k1_ecdsa_sign(ctx, &signature, msg, key, NULL, NULL); - VALGRIND_MAKE_MEM_DEFINED(&signature, sizeof(secp256k1_ecdsa_signature)); - VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); + SECP256K1_CHECKMEM_DEFINE(&signature, sizeof(secp256k1_ecdsa_signature)); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret); CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, sig, &siglen, &signature)); #ifdef ENABLE_MODULE_ECDH /* Test ECDH. */ - VALGRIND_MAKE_MEM_UNDEFINED(key, 32); + SECP256K1_CHECKMEM_UNDEFINE(key, 32); ret = secp256k1_ecdh(ctx, msg, &pubkey, key, NULL, NULL); - VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret == 1); #endif #ifdef ENABLE_MODULE_RECOVERY /* Test signing a recoverable signature. */ - VALGRIND_MAKE_MEM_UNDEFINED(key, 32); + SECP256K1_CHECKMEM_UNDEFINE(key, 32); ret = secp256k1_ecdsa_sign_recoverable(ctx, &recoverable_signature, msg, key, NULL, NULL); - VALGRIND_MAKE_MEM_DEFINED(&recoverable_signature, sizeof(recoverable_signature)); - VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); + SECP256K1_CHECKMEM_DEFINE(&recoverable_signature, sizeof(recoverable_signature)); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret); CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, sig, &recid, &recoverable_signature)); CHECK(recid >= 0 && recid <= 3); #endif - VALGRIND_MAKE_MEM_UNDEFINED(key, 32); + SECP256K1_CHECKMEM_UNDEFINE(key, 32); ret = secp256k1_ec_seckey_verify(ctx, key); - VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret == 1); - VALGRIND_MAKE_MEM_UNDEFINED(key, 32); + SECP256K1_CHECKMEM_UNDEFINE(key, 32); ret = secp256k1_ec_seckey_negate(ctx, key); - VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret == 1); - VALGRIND_MAKE_MEM_UNDEFINED(key, 32); - VALGRIND_MAKE_MEM_UNDEFINED(msg, 32); + SECP256K1_CHECKMEM_UNDEFINE(key, 32); + SECP256K1_CHECKMEM_UNDEFINE(msg, 32); ret = secp256k1_ec_seckey_tweak_add(ctx, key, msg); - VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret == 1); - VALGRIND_MAKE_MEM_UNDEFINED(key, 32); - VALGRIND_MAKE_MEM_UNDEFINED(msg, 32); + SECP256K1_CHECKMEM_UNDEFINE(key, 32); + SECP256K1_CHECKMEM_UNDEFINE(msg, 32); ret = secp256k1_ec_seckey_tweak_mul(ctx, key, msg); - VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret == 1); /* Test keypair_create and keypair_xonly_tweak_add. */ #ifdef ENABLE_MODULE_EXTRAKEYS - VALGRIND_MAKE_MEM_UNDEFINED(key, 32); + SECP256K1_CHECKMEM_UNDEFINE(key, 32); ret = secp256k1_keypair_create(ctx, &keypair, key); - VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret == 1); /* The tweak is not treated as a secret in keypair_tweak_add */ - VALGRIND_MAKE_MEM_DEFINED(msg, 32); + SECP256K1_CHECKMEM_DEFINE(msg, 32); ret = secp256k1_keypair_xonly_tweak_add(ctx, &keypair, msg); - VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret == 1); - VALGRIND_MAKE_MEM_UNDEFINED(key, 32); - VALGRIND_MAKE_MEM_UNDEFINED(&keypair, sizeof(keypair)); + SECP256K1_CHECKMEM_UNDEFINE(key, 32); + SECP256K1_CHECKMEM_UNDEFINE(&keypair, sizeof(keypair)); ret = secp256k1_keypair_sec(ctx, key, &keypair); - VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret == 1); #endif #ifdef ENABLE_MODULE_SCHNORRSIG - VALGRIND_MAKE_MEM_UNDEFINED(key, 32); + SECP256K1_CHECKMEM_UNDEFINE(key, 32); ret = secp256k1_keypair_create(ctx, &keypair, key); - VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret == 1); ret = secp256k1_schnorrsig_sign32(ctx, sig, msg, &keypair, NULL); - VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret == 1); #endif } From 8dc64079eb1db5abafbc18e335bcf179ae851ae8 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Tue, 6 Dec 2022 16:41:35 -0500 Subject: [PATCH 07/47] Add compile-time error to valgrind_ctime_test --- src/valgrind_ctime_test.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/valgrind_ctime_test.c b/src/valgrind_ctime_test.c index 2e2b6b14..a727a143 100644 --- a/src/valgrind_ctime_test.c +++ b/src/valgrind_ctime_test.c @@ -10,6 +10,10 @@ #include "assumptions.h" #include "checkmem.h" +#if !SECP256K1_CHECKMEM_ENABLED +# error "This tool cannot be compiled without memory-checking interface (valgrind)" +#endif + #ifdef ENABLE_MODULE_ECDH # include "../include/secp256k1_ecdh.h" #endif From 8e11f89a685063221fa4c2df0ee750d997aee386 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Tue, 6 Dec 2022 18:38:32 -0500 Subject: [PATCH 08/47] Add support for msan integration to checkmem.h --- src/checkmem.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/checkmem.h b/src/checkmem.h index 55d96c3d..571e4cc3 100644 --- a/src/checkmem.h +++ b/src/checkmem.h @@ -39,6 +39,20 @@ /* Define a statement-like macro that ignores the arguments. */ #define SECP256K1_CHECKMEM_NOOP(p, len) do { (void)(p); (void)(len); } while(0) +/* If compiling under msan, map the SECP256K1_CHECKMEM_* functionality to msan. + * Choose this preferentially, even when VALGRIND is defined, as msan-compiled + * binaries can't be run under valgrind anyway. */ +#if defined(__has_feature) +# if __has_feature(memory_sanitizer) +# include +# define SECP256K1_CHECKMEM_ENABLED 1 +# define SECP256K1_CHECKMEM_UNDEFINE(p, len) __msan_allocated_memory((p), (len)) +# define SECP256K1_CHECKMEM_DEFINE(p, len) __msan_unpoison((p), (len)) +# define SECP256K1_CHECKMEM_CHECK(p, len) __msan_check_mem_is_initialized((p), (len)) +# define SECP256K1_CHECKMEM_RUNNING() (1) +# endif +#endif + /* If valgrind integration is desired (through the VALGRIND define), implement the * SECP256K1_CHECKMEM_* macros using valgrind. */ #if !defined SECP256K1_CHECKMEM_ENABLED From 6eed6c18ded7bd89d82fe1ebb13b488a2cf5e567 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Tue, 6 Dec 2022 18:41:47 -0500 Subject: [PATCH 09/47] Update error messages to suggest msan as well --- src/valgrind_ctime_test.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/valgrind_ctime_test.c b/src/valgrind_ctime_test.c index a727a143..aad02b6b 100644 --- a/src/valgrind_ctime_test.c +++ b/src/valgrind_ctime_test.c @@ -11,7 +11,7 @@ #include "checkmem.h" #if !SECP256K1_CHECKMEM_ENABLED -# error "This tool cannot be compiled without memory-checking interface (valgrind)" +# error "This tool cannot be compiled without memory-checking interface (valgrind or msan)" #endif #ifdef ENABLE_MODULE_ECDH @@ -38,7 +38,7 @@ int main(void) { int ret, i; if (!SECP256K1_CHECKMEM_RUNNING()) { - fprintf(stderr, "This test can only usefully be run inside valgrind.\n"); + fprintf(stderr, "Unless compiled under msan, this test can only usefully be run inside valgrind.\n"); fprintf(stderr, "Usage: libtool --mode=execute valgrind ./valgrind_ctime_test\n"); return 1; } From 5048be17e93a21ab2e33b939b40339ed4861a692 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Tue, 6 Dec 2022 18:45:43 -0500 Subject: [PATCH 10/47] Rename valgrind_ctime_test -> ctime_tests --- .cirrus.yml | 4 ++-- .gitignore | 2 +- Makefile.am | 8 ++++---- ci/cirrus.sh | 2 +- doc/safegcd_implementation.md | 2 +- src/{valgrind_ctime_test.c => ctime_tests.c} | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) rename src/{valgrind_ctime_test.c => ctime_tests.c} (99%) diff --git a/.cirrus.yml b/.cirrus.yml index aabfea22..258bfab6 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -40,8 +40,8 @@ cat_logs_snippet: &CAT_LOGS - cat noverify_tests.log || true cat_exhaustive_tests_log_script: - cat exhaustive_tests.log || true - cat_valgrind_ctime_test_log_script: - - cat valgrind_ctime_test.log || true + cat_ctime_tests_log_script: + - cat ctime_tests.log || true cat_bench_log_script: - cat bench.log || true cat_config_log_script: diff --git a/.gitignore b/.gitignore index c68645b9..6ef3e2df 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,7 @@ tests exhaustive_tests precompute_ecmult_gen precompute_ecmult -valgrind_ctime_test +ctime_tests ecdh_example ecdsa_example schnorr_example diff --git a/Makefile.am b/Makefile.am index b5925235..b7500bc0 100644 --- a/Makefile.am +++ b/Makefile.am @@ -120,10 +120,10 @@ noverify_tests_CPPFLAGS = $(SECP_INCLUDES) $(SECP_TEST_INCLUDES) $(SECP_CONFIG_D noverify_tests_LDADD = $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB) $(PRECOMPUTED_LIB) noverify_tests_LDFLAGS = -static if VALGRIND_ENABLED -noinst_PROGRAMS += valgrind_ctime_test -valgrind_ctime_test_SOURCES = src/valgrind_ctime_test.c -valgrind_ctime_test_LDADD = libsecp256k1.la $(SECP_LIBS) $(COMMON_LIB) -valgrind_ctime_test_CPPFLAGS = $(SECP_CONFIG_DEFINES) +noinst_PROGRAMS += ctime_tests +ctime_tests_SOURCES = src/ctime_tests.c +ctime_tests_LDADD = libsecp256k1.la $(SECP_LIBS) $(COMMON_LIB) +ctime_tests_CPPFLAGS = $(SECP_CONFIG_DEFINES) endif if !ENABLE_COVERAGE TESTS += tests diff --git a/ci/cirrus.sh b/ci/cirrus.sh index 80ce8f27..814c4c93 100755 --- a/ci/cirrus.sh +++ b/ci/cirrus.sh @@ -95,7 +95,7 @@ fi if [ "$CTIMETEST" = "yes" ] then - ./libtool --mode=execute valgrind --error-exitcode=42 ./valgrind_ctime_test > valgrind_ctime_test.log 2>&1 + ./libtool --mode=execute valgrind --error-exitcode=42 ./ctime_tests > ctime_tests.log 2>&1 fi # Rebuild precomputed files (if not cross-compiling). diff --git a/doc/safegcd_implementation.md b/doc/safegcd_implementation.md index 063aa8ef..5216231e 100644 --- a/doc/safegcd_implementation.md +++ b/doc/safegcd_implementation.md @@ -410,7 +410,7 @@ sufficient even. Given that every loop iteration performs *N* divsteps, it will To deal with the branches in `divsteps_n_matrix` we will replace them with constant-time bitwise operations (and hope the C compiler isn't smart enough to turn them back into branches; see -`valgrind_ctime_test.c` for automated tests that this isn't the case). To do so, observe that a +`ctime_tests.c` for automated tests that this isn't the case). To do so, observe that a divstep can be written instead as (compare to the inner loop of `gcd` in section 1). ```python diff --git a/src/valgrind_ctime_test.c b/src/ctime_tests.c similarity index 99% rename from src/valgrind_ctime_test.c rename to src/ctime_tests.c index aad02b6b..2b295686 100644 --- a/src/valgrind_ctime_test.c +++ b/src/ctime_tests.c @@ -39,7 +39,7 @@ int main(void) { if (!SECP256K1_CHECKMEM_RUNNING()) { fprintf(stderr, "Unless compiled under msan, this test can only usefully be run inside valgrind.\n"); - fprintf(stderr, "Usage: libtool --mode=execute valgrind ./valgrind_ctime_test\n"); + fprintf(stderr, "Usage: libtool --mode=execute valgrind ./ctime_tests\n"); return 1; } ctx = secp256k1_context_create(SECP256K1_CONTEXT_DECLASSIFY); From 18974061a3ffef514cc393768401b2f104fe6cef Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Tue, 6 Dec 2022 23:12:15 -0500 Subject: [PATCH 11/47] Make ctime tests building configurable --- Makefile.am | 13 +++++++------ configure.ac | 11 ++++++++++- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/Makefile.am b/Makefile.am index b7500bc0..7aefce49 100644 --- a/Makefile.am +++ b/Makefile.am @@ -119,12 +119,6 @@ noverify_tests_SOURCES = src/tests.c noverify_tests_CPPFLAGS = $(SECP_INCLUDES) $(SECP_TEST_INCLUDES) $(SECP_CONFIG_DEFINES) noverify_tests_LDADD = $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB) $(PRECOMPUTED_LIB) noverify_tests_LDFLAGS = -static -if VALGRIND_ENABLED -noinst_PROGRAMS += ctime_tests -ctime_tests_SOURCES = src/ctime_tests.c -ctime_tests_LDADD = libsecp256k1.la $(SECP_LIBS) $(COMMON_LIB) -ctime_tests_CPPFLAGS = $(SECP_CONFIG_DEFINES) -endif if !ENABLE_COVERAGE TESTS += tests noinst_PROGRAMS += tests @@ -135,6 +129,13 @@ tests_LDFLAGS = $(noverify_tests_LDFLAGS) endif endif +if USE_CTIME_TESTS +noinst_PROGRAMS += ctime_tests +ctime_tests_SOURCES = src/ctime_tests.c +ctime_tests_LDADD = libsecp256k1.la $(SECP_LIBS) $(COMMON_LIB) +ctime_tests_CPPFLAGS = $(SECP_CONFIG_DEFINES) +endif + if USE_EXHAUSTIVE_TESTS noinst_PROGRAMS += exhaustive_tests exhaustive_tests_SOURCES = src/tests_exhaustive.c diff --git a/configure.ac b/configure.ac index 88b0ee58..cb5d0397 100644 --- a/configure.ac +++ b/configure.ac @@ -142,6 +142,10 @@ AC_ARG_ENABLE(tests, AS_HELP_STRING([--enable-tests],[compile tests [default=yes]]), [], [SECP_SET_DEFAULT([enable_tests], [yes], [yes])]) +AC_ARG_ENABLE(ctime_tests, + AS_HELP_STRING([--enable-ctime-tests],[compile constant-time tests [default=yes if valgrind enabled]]), [], + [SECP_SET_DEFAULT([enable_ctime_tests], [auto], [auto])]) + AC_ARG_ENABLE(experimental, AS_HELP_STRING([--enable-experimental],[allow experimental configure options [default=no]]), [], [SECP_SET_DEFAULT([enable_experimental], [no], [yes])]) @@ -225,7 +229,10 @@ else enable_valgrind=yes fi fi -AM_CONDITIONAL([VALGRIND_ENABLED],[test "$enable_valgrind" = "yes"]) + +if test x"$enable_ctime_tests" = x"auto"; then + enable_ctime_tests=$enable_valgrind +fi if test x"$enable_coverage" = x"yes"; then SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DCOVERAGE=1" @@ -407,6 +414,7 @@ AC_SUBST(SECP_CFLAGS) AC_SUBST(SECP_CONFIG_DEFINES) AM_CONDITIONAL([ENABLE_COVERAGE], [test x"$enable_coverage" = x"yes"]) AM_CONDITIONAL([USE_TESTS], [test x"$enable_tests" != x"no"]) +AM_CONDITIONAL([USE_CTIME_TESTS], [test x"$enable_ctime_tests" = x"yes"]) AM_CONDITIONAL([USE_EXHAUSTIVE_TESTS], [test x"$enable_exhaustive_tests" != x"no"]) AM_CONDITIONAL([USE_EXAMPLES], [test x"$enable_examples" != x"no"]) AM_CONDITIONAL([USE_BENCHMARK], [test x"$enable_benchmark" = x"yes"]) @@ -428,6 +436,7 @@ echo "Build Options:" echo " with external callbacks = $enable_external_default_callbacks" echo " with benchmarks = $enable_benchmark" echo " with tests = $enable_tests" +echo " with ctime tests = $enable_ctime_tests" echo " with coverage = $enable_coverage" echo " with examples = $enable_examples" echo " module ecdh = $enable_module_ecdh" From 5e2e6fcfc0ebcdaad96fda9db9b8946d8bcdc8e5 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Tue, 6 Dec 2022 18:53:51 -0500 Subject: [PATCH 12/47] Run ctime test in Linux MSan CI job --- .cirrus.yml | 3 ++- ci/cirrus.sh | 20 +++++++++++++------- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index 258bfab6..0f644a67 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -330,10 +330,11 @@ task: ECDH: yes RECOVERY: yes SCHNORRSIG: yes - CTIMETEST: no + CTIMETEST: yes CC: clang SECP256K1_TEST_ITERS: 32 ASM: no + WITH_VALGRIND: no container: memory: 2G matrix: diff --git a/ci/cirrus.sh b/ci/cirrus.sh index 814c4c93..2a88915e 100755 --- a/ci/cirrus.sh +++ b/ci/cirrus.sh @@ -62,6 +62,7 @@ fi --enable-module-ecdh="$ECDH" --enable-module-recovery="$RECOVERY" \ --enable-module-schnorrsig="$SCHNORRSIG" \ --enable-examples="$EXAMPLES" \ + --enable-ctime-tests="$CTIMETEST" \ --with-valgrind="$WITH_VALGRIND" \ --host="$HOST" $EXTRAFLAGS @@ -78,14 +79,15 @@ export LOG_COMPILER="$WRAPPER_CMD" make "$BUILD" +# Using the local `libtool` because on macOS the system's libtool has nothing to do with GNU libtool +EXEC='./libtool --mode=execute' +if [ -n "$WRAPPER_CMD" ] +then + EXEC="$EXEC $WRAPPER_CMD" +fi + if [ "$BENCH" = "yes" ] then - # Using the local `libtool` because on macOS the system's libtool has nothing to do with GNU libtool - EXEC='./libtool --mode=execute' - if [ -n "$WRAPPER_CMD" ] - then - EXEC="$EXEC $WRAPPER_CMD" - fi { $EXEC ./bench_ecmult $EXEC ./bench_internal @@ -95,7 +97,11 @@ fi if [ "$CTIMETEST" = "yes" ] then - ./libtool --mode=execute valgrind --error-exitcode=42 ./ctime_tests > ctime_tests.log 2>&1 + if [ "$WITH_VALGRIND" = "yes" ]; then + ./libtool --mode=execute valgrind --error-exitcode=42 ./ctime_tests > ctime_tests.log 2>&1 + else + $EXEC ./ctime_tests > ctime_tests.log 2>&1 + fi fi # Rebuild precomputed files (if not cross-compiling). From 74b026f05d52216fa4c83cbfada416a30ddfc9b9 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Tue, 20 Dec 2022 12:25:48 -0500 Subject: [PATCH 13/47] Add runtime checking for DECLASSIFY flag --- src/secp256k1.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/secp256k1.c b/src/secp256k1.c index 89bb0af8..6c91a761 100644 --- a/src/secp256k1.c +++ b/src/secp256k1.c @@ -99,6 +99,12 @@ size_t secp256k1_context_preallocated_size(unsigned int flags) { return 0; } + if (EXPECT(!SECP256K1_CHECKMEM_RUNNING() && (flags & SECP256K1_FLAGS_BIT_CONTEXT_DECLASSIFY), 0)) { + secp256k1_callback_call(&default_illegal_callback, + "Declassify flag requires running with memory checking"); + return 0; + } + return ret; } From 0f088ec11263261497661215c110a4c395acc0ac Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Tue, 20 Dec 2022 12:28:48 -0500 Subject: [PATCH 14/47] Rename CTIMETEST -> CTIMETESTS --- .cirrus.yml | 24 ++++++++++++------------ ci/cirrus.sh | 6 +++--- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index 0f644a67..ac682e50 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -23,7 +23,7 @@ env: SECP256K1_TEST_ITERS: BENCH: yes SECP256K1_BENCH_ITERS: 2 - CTIMETEST: yes + CTIMETESTS: yes # Compile and run the tests EXAMPLES: yes @@ -81,9 +81,9 @@ task: - env: {WIDEMUL: int128, ECDH: yes, SCHNORRSIG: yes} - env: {WIDEMUL: int128, ASM: x86_64} - env: { RECOVERY: yes, SCHNORRSIG: yes} - - env: {BUILD: distcheck, WITH_VALGRIND: no, CTIMETEST: no, BENCH: no} + - env: {BUILD: distcheck, WITH_VALGRIND: no, CTIMETESTS: no, BENCH: no} - env: {CPPFLAGS: -DDETERMINISTIC} - - env: {CFLAGS: -O0, CTIMETEST: no} + - env: {CFLAGS: -O0, CTIMETESTS: no} - env: { ECMULTGENPRECISION: 2, ECMULTWINDOW: 2 } - env: { ECMULTGENPRECISION: 8, ECMULTWINDOW: 4 } matrix: @@ -128,7 +128,7 @@ task: env: ASM: no WITH_VALGRIND: no - CTIMETEST: no + CTIMETESTS: no matrix: - env: CC: gcc @@ -153,7 +153,7 @@ task: ECDH: yes RECOVERY: yes SCHNORRSIG: yes - CTIMETEST: no + CTIMETESTS: no << : *MERGE_BASE test_script: # https://sourceware.org/bugzilla/show_bug.cgi?id=27008 @@ -172,7 +172,7 @@ task: ECDH: yes RECOVERY: yes SCHNORRSIG: yes - CTIMETEST: no + CTIMETESTS: no matrix: - env: {} - env: {EXPERIMENTAL: yes, ASM: arm} @@ -192,7 +192,7 @@ task: ECDH: yes RECOVERY: yes SCHNORRSIG: yes - CTIMETEST: no + CTIMETESTS: no << : *MERGE_BASE test_script: - ./ci/cirrus.sh @@ -209,7 +209,7 @@ task: ECDH: yes RECOVERY: yes SCHNORRSIG: yes - CTIMETEST: no + CTIMETESTS: no << : *MERGE_BASE test_script: - ./ci/cirrus.sh @@ -223,7 +223,7 @@ task: ECDH: yes RECOVERY: yes SCHNORRSIG: yes - CTIMETEST: no + CTIMETESTS: no matrix: - name: "x86_64 (mingw32-w64): Windows (Debian stable, Wine)" env: @@ -246,7 +246,7 @@ task: RECOVERY: yes EXPERIMENTAL: yes SCHNORRSIG: yes - CTIMETEST: no + CTIMETESTS: no # Use a MinGW-w64 host to tell ./configure we're building for Windows. # This will detect some MinGW-w64 tools but then make will need only # the MSVC tools CC, AR and NM as specified below. @@ -285,7 +285,7 @@ task: ECDH: yes RECOVERY: yes SCHNORRSIG: yes - CTIMETEST: no + CTIMETESTS: no matrix: - name: "Valgrind (memcheck)" container: @@ -330,7 +330,7 @@ task: ECDH: yes RECOVERY: yes SCHNORRSIG: yes - CTIMETEST: yes + CTIMETESTS: yes CC: clang SECP256K1_TEST_ITERS: 32 ASM: no diff --git a/ci/cirrus.sh b/ci/cirrus.sh index 2a88915e..e1ca35e3 100755 --- a/ci/cirrus.sh +++ b/ci/cirrus.sh @@ -13,7 +13,7 @@ print_environment() { for var in WERROR_CFLAGS MAKEFLAGS BUILD \ ECMULTWINDOW ECMULTGENPRECISION ASM WIDEMUL WITH_VALGRIND EXTRAFLAGS \ EXPERIMENTAL ECDH RECOVERY SCHNORRSIG \ - SECP256K1_TEST_ITERS BENCH SECP256K1_BENCH_ITERS CTIMETEST\ + SECP256K1_TEST_ITERS BENCH SECP256K1_BENCH_ITERS CTIMETESTS\ EXAMPLES \ HOST WRAPPER_CMD \ CC CFLAGS CPPFLAGS AR NM @@ -62,7 +62,7 @@ fi --enable-module-ecdh="$ECDH" --enable-module-recovery="$RECOVERY" \ --enable-module-schnorrsig="$SCHNORRSIG" \ --enable-examples="$EXAMPLES" \ - --enable-ctime-tests="$CTIMETEST" \ + --enable-ctime-tests="$CTIMETESTS" \ --with-valgrind="$WITH_VALGRIND" \ --host="$HOST" $EXTRAFLAGS @@ -95,7 +95,7 @@ then } >> bench.log 2>&1 fi -if [ "$CTIMETEST" = "yes" ] +if [ "$CTIMETESTS" = "yes" ] then if [ "$WITH_VALGRIND" = "yes" ]; then ./libtool --mode=execute valgrind --error-exitcode=42 ./ctime_tests > ctime_tests.log 2>&1 From d4a6b58df7490ff9c656e158f246cf396b4cfa72 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Fri, 13 Jan 2023 18:46:57 +0000 Subject: [PATCH 15/47] Add `noverify_tests` to `.gitignore` --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index c68645b9..e6e36c7b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ bench bench_ecmult bench_internal +noverify_tests tests exhaustive_tests precompute_ecmult_gen From 4934aa79958b506a6e9cfcfe30a8f685db3f5f5f Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Tue, 10 Jan 2023 16:10:45 -0500 Subject: [PATCH 16/47] Switch to exhaustive groups with small B coefficient --- sage/gen_exhaustive_groups.sage | 191 +++++++++++-------- src/group_impl.h | 68 ++++--- src/modules/recovery/tests_exhaustive_impl.h | 3 +- src/precomputed_ecmult.h | 4 +- src/scalar_impl.h | 7 +- 5 files changed, 169 insertions(+), 104 deletions(-) diff --git a/sage/gen_exhaustive_groups.sage b/sage/gen_exhaustive_groups.sage index 01d15dcd..60265809 100644 --- a/sage/gen_exhaustive_groups.sage +++ b/sage/gen_exhaustive_groups.sage @@ -1,124 +1,161 @@ load("secp256k1_params.sage") +MAX_ORDER = 1000 + +# Set of (curve) orders we have encountered so far. orders_done = set() -results = {} -first = True + +# Map from (subgroup) orders to [b, int(gen.x), int(gen.y), gen, lambda] for those subgroups. +solutions = {} + +# Iterate over curves of the form y^2 = x^3 + B. for b in range(1, P): - # There are only 6 curves (up to isomorphism) of the form y^2=x^3+B. Stop once we have tried all. + # There are only 6 curves (up to isomorphism) of the form y^2 = x^3 + B. Stop once we have tried all. if len(orders_done) == 6: break E = EllipticCurve(F, [0, b]) print("Analyzing curve y^2 = x^3 + %i" % b) n = E.order() + # Skip curves with an order we've already tried if n in orders_done: print("- Isomorphic to earlier curve") + print() continue orders_done.add(n) + # Skip curves isomorphic to the real secp256k1 if n.is_pseudoprime(): - print(" - Isomorphic to secp256k1") + assert E.is_isomorphic(C) + print("- Isomorphic to secp256k1") + print() continue - print("- Finding subgroups") + print("- Finding prime subgroups") - # Find what prime subgroups exist - for f, _ in n.factor(): - print("- Analyzing subgroup of order %i" % f) - # Skip subgroups of order >1000 - if f < 4 or f > 1000: - print(" - Bad size") - continue + # Map from group_order to a set of independent generators for that order. + curve_gens = {} - # Iterate over X coordinates until we find one that is on the curve, has order f, - # and for which curve isomorphism exists that maps it to X coordinate 1. - for x in range(1, P): - # Skip X coordinates not on the curve, and construct the full point otherwise. - if not E.is_x_coord(x): + for g in E.gens(): + # Find what prime subgroups of group generated by g exist. + g_order = g.order() + for f, _ in g.order().factor(): + # Skip subgroups that have bad size. + if f < 4: + print(f" - Subgroup of size {f}: too small") continue - G = E.lift_x(F(x)) - - print(" - Analyzing (multiples of) point with X=%i" % x) - - # Skip points whose order is not a multiple of f. Project the point to have - # order f otherwise. - if (G.order() % f): - print(" - Bad order") + if f > MAX_ORDER: + print(f" - Subgroup of size {f}: too large") continue - G = G * (G.order() // f) + + # Construct a generator for that subgroup. + gen = g * (g_order // f) + assert(gen.order() == f) + + # Add to set the minimal multiple of gen. + curve_gens.setdefault(f, set()).add(min([j*gen for j in range(1, f)])) + print(f" - Subgroup of size {f}: ok") + + for f in sorted(curve_gens.keys()): + print(f"- Constructing group of order {f}") + cbrts = sorted([int(c) for c in Integers(f)(1).nth_root(3, all=true) if c != 1]) + gens = list(curve_gens[f]) + sol_count = 0 + no_endo_count = 0 + + # Consider all non-zero linear combinations of the independent generators. + for j in range(1, f**len(gens)): + gen = sum(gens[k] * ((j // f**k) % f) for k in range(len(gens))) + assert not gen.is_zero() + assert (f*gen).is_zero() # Find lambda for endomorphism. Skip if none can be found. lam = None - for l in Integers(f)(1).nth_root(3, all=True): - if int(l)*G == E(BETA*G[0], G[1]): - lam = int(l) + for l in cbrts: + if l*gen == E(BETA*gen[0], gen[1]): + lam = l break + if lam is None: - print(" - No endomorphism for this subgroup") - break + no_endo_count += 1 + else: + sol_count += 1 + solutions.setdefault(f, []).append((b, int(gen[0]), int(gen[1]), gen, lam)) - # Now look for an isomorphism of the curve that gives this point an X - # coordinate equal to 1. - # If (x,y) is on y^2 = x^3 + b, then (a^2*x, a^3*y) is on y^2 = x^3 + a^6*b. - # So look for m=a^2=1/x. - m = F(1)/G[0] - if not m.is_square(): - print(" - No curve isomorphism maps it to a point with X=1") - continue - a = m.sqrt() - rb = a^6*b - RE = EllipticCurve(F, [0, rb]) + print(f" - Found {sol_count} generators (plus {no_endo_count} without endomorphism)") - # Use as generator twice the image of G under the above isormorphism. - # This means that generator*(1/2 mod f) will have X coordinate 1. - RG = RE(1, a^3*G[1]) * 2 - # And even Y coordinate. - if int(RG[1]) % 2: - RG = -RG - assert(RG.order() == f) - assert(lam*RG == RE(BETA*RG[0], RG[1])) + print() - # We have found curve RE:y^2=x^3+rb with generator RG of order f. Remember it - results[f] = {"b": rb, "G": RG, "lambda": lam} - print(" - Found solution") - break +def output_generator(g, name): + print(f"#define {name} SECP256K1_GE_CONST(\\") + print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x,\\" % tuple((int(g[0]) >> (32 * (7 - i))) & 0xffffffff for i in range(4))) + print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x,\\" % tuple((int(g[0]) >> (32 * (7 - i))) & 0xffffffff for i in range(4, 8))) + print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x,\\" % tuple((int(g[1]) >> (32 * (7 - i))) & 0xffffffff for i in range(4))) + print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x\\" % tuple((int(g[1]) >> (32 * (7 - i))) & 0xffffffff for i in range(4, 8))) + print(")") - print("") - -print("") -print("") -print("/* To be put in src/group_impl.h: */") -first = True -for f in sorted(results.keys()): - b = results[f]["b"] - G = results[f]["G"] - print("# %s EXHAUSTIVE_TEST_ORDER == %i" % ("if" if first else "elif", f)) - first = False - print("static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST(") - print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x," % tuple((int(G[0]) >> (32 * (7 - i))) & 0xffffffff for i in range(4))) - print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x," % tuple((int(G[0]) >> (32 * (7 - i))) & 0xffffffff for i in range(4, 8))) - print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x," % tuple((int(G[1]) >> (32 * (7 - i))) & 0xffffffff for i in range(4))) - print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x" % tuple((int(G[1]) >> (32 * (7 - i))) & 0xffffffff for i in range(4, 8))) - print(");") +def output_b(b): print("static const secp256k1_fe secp256k1_fe_const_b = SECP256K1_FE_CONST(") print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x," % tuple((int(b) >> (32 * (7 - i))) & 0xffffffff for i in range(4))) print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x" % tuple((int(b) >> (32 * (7 - i))) & 0xffffffff for i in range(4, 8))) print(");") + +print() +print("To be put in src/group_impl.h:") +print() +print("/* Begin of section generated by sage/gen_exhaustive_groups.sage. */") +for f in sorted(solutions.keys()): + # Use as generator/2 the one with lowest b, and lowest (x, y) generator (interpreted as non-negative integers). + b, _, _, HALF_G, lam = min(solutions[f]) + output_generator(2 * HALF_G, f"SECP256K1_G_ORDER_{f}") +print("/** Generator for secp256k1, value 'g' defined in") +print(" * \"Standards for Efficient Cryptography\" (SEC2) 2.7.1.") +print(" */") +output_generator(G, "SECP256K1_G") +print("/* These exhaustive group test orders and generators are chosen such that:") +print(" * - The field size is equal to that of secp256k1, so field code is the same.") +print(" * - The curve equation is of the form y^2=x^3+B for some small constant B.") +print(" * - The subgroup has a generator 2*P, where P.x is as small as possible.") +print(f" * - The subgroup has size less than {MAX_ORDER} to permit exhaustive testing.") +print(" * - The subgroup admits an endomorphism of the form lambda*(x,y) == (beta*x,y).") +print(" */") +print("#if defined(EXHAUSTIVE_TEST_ORDER)") +first = True +for f in sorted(solutions.keys()): + b, _, _, _, lam = min(solutions[f]) + print(f"# {'if' if first else 'elif'} EXHAUSTIVE_TEST_ORDER == {f}") + first = False + print() + print(f"static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_G_ORDER_{f};") + print("") + output_b(b) + print() print("# else") print("# error No known generator for the specified exhaustive test group order.") print("# endif") +print("#else") +print() +print("static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_G;") +print("") +output_b(7) +print() +print("#endif") +print("/* End of section generated by sage/gen_exhaustive_groups.sage. */") -print("") -print("") -print("/* To be put in src/scalar_impl.h: */") + +print() +print() +print("To be put in src/scalar_impl.h:") +print() +print("/* Begin of section generated by sage/gen_exhaustive_groups.sage. */") first = True -for f in sorted(results.keys()): - lam = results[f]["lambda"] +for f in sorted(solutions.keys()): + _, _, _, _, lam = min(solutions[f]) print("# %s EXHAUSTIVE_TEST_ORDER == %i" % ("if" if first else "elif", f)) first = False print("# define EXHAUSTIVE_TEST_LAMBDA %i" % lam) print("# else") print("# error No known lambda for the specified exhaustive test group order.") print("# endif") -print("") +print("/* End of section generated by sage/gen_exhaustive_groups.sage. */") diff --git a/src/group_impl.h b/src/group_impl.h index dfe6e32c..ed2b50b8 100644 --- a/src/group_impl.h +++ b/src/group_impl.h @@ -10,59 +10,83 @@ #include "field.h" #include "group.h" +/* Begin of section generated by sage/gen_exhaustive_groups.sage. */ +#define SECP256K1_G_ORDER_7 SECP256K1_GE_CONST(\ + 0x66625d13, 0x317ffe44, 0x63d32cff, 0x1ca02b9b,\ + 0xe5c6d070, 0x50b4b05e, 0x81cc30db, 0xf5166f0a,\ + 0x1e60e897, 0xa7c00c7c, 0x2df53eb6, 0x98274ff4,\ + 0x64252f42, 0x8ca44e17, 0x3b25418c, 0xff4ab0cf\ +) #define SECP256K1_G_ORDER_13 SECP256K1_GE_CONST(\ - 0xc3459c3d, 0x35326167, 0xcd86cce8, 0x07a2417f,\ - 0x5b8bd567, 0xde8538ee, 0x0d507b0c, 0xd128f5bb,\ - 0x8e467fec, 0xcd30000a, 0x6cc1184e, 0x25d382c2,\ - 0xa2f4494e, 0x2fbe9abc, 0x8b64abac, 0xd005fb24\ + 0xa2482ff8, 0x4bf34edf, 0xa51262fd, 0xe57921db,\ + 0xe0dd2cb7, 0xa5914790, 0xbc71631f, 0xc09704fb,\ + 0x942536cb, 0xa3e49492, 0x3a701cc3, 0xee3e443f,\ + 0xdf182aa9, 0x15b8aa6a, 0x166d3b19, 0xba84b045\ ) #define SECP256K1_G_ORDER_199 SECP256K1_GE_CONST(\ - 0x226e653f, 0xc8df7744, 0x9bacbf12, 0x7d1dcbf9,\ - 0x87f05b2a, 0xe7edbd28, 0x1f564575, 0xc48dcf18,\ - 0xa13872c2, 0xe933bb17, 0x5d9ffd5b, 0xb5b6e10c,\ - 0x57fe3c00, 0xbaaaa15a, 0xe003ec3e, 0x9c269bae\ + 0x7fb07b5c, 0xd07c3bda, 0x553902e2, 0x7a87ea2c,\ + 0x35108a7f, 0x051f41e5, 0xb76abad5, 0x1f2703ad,\ + 0x0a251539, 0x5b4c4438, 0x952a634f, 0xac10dd4d,\ + 0x6d6f4745, 0x98990c27, 0x3a4f3116, 0xd32ff969\ ) /** Generator for secp256k1, value 'g' defined in * "Standards for Efficient Cryptography" (SEC2) 2.7.1. */ #define SECP256K1_G SECP256K1_GE_CONST(\ - 0x79BE667EUL, 0xF9DCBBACUL, 0x55A06295UL, 0xCE870B07UL,\ - 0x029BFCDBUL, 0x2DCE28D9UL, 0x59F2815BUL, 0x16F81798UL,\ - 0x483ADA77UL, 0x26A3C465UL, 0x5DA4FBFCUL, 0x0E1108A8UL,\ - 0xFD17B448UL, 0xA6855419UL, 0x9C47D08FUL, 0xFB10D4B8UL\ + 0x79be667e, 0xf9dcbbac, 0x55a06295, 0xce870b07,\ + 0x029bfcdb, 0x2dce28d9, 0x59f2815b, 0x16f81798,\ + 0x483ada77, 0x26a3c465, 0x5da4fbfc, 0x0e1108a8,\ + 0xfd17b448, 0xa6855419, 0x9c47d08f, 0xfb10d4b8\ ) /* These exhaustive group test orders and generators are chosen such that: * - The field size is equal to that of secp256k1, so field code is the same. - * - The curve equation is of the form y^2=x^3+B for some constant B. - * - The subgroup has a generator 2*P, where P.x=1. + * - The curve equation is of the form y^2=x^3+B for some small constant B. + * - The subgroup has a generator 2*P, where P.x is as small as possible. * - The subgroup has size less than 1000 to permit exhaustive testing. * - The subgroup admits an endomorphism of the form lambda*(x,y) == (beta*x,y). - * - * These parameters are generated using sage/gen_exhaustive_groups.sage. */ #if defined(EXHAUSTIVE_TEST_ORDER) -# if EXHAUSTIVE_TEST_ORDER == 13 +# if EXHAUSTIVE_TEST_ORDER == 7 + +static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_G_ORDER_7; + +static const secp256k1_fe secp256k1_fe_const_b = SECP256K1_FE_CONST( + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000006 +); + +# elif EXHAUSTIVE_TEST_ORDER == 13 + static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_G_ORDER_13; static const secp256k1_fe secp256k1_fe_const_b = SECP256K1_FE_CONST( - 0x3d3486b2, 0x159a9ca5, 0xc75638be, 0xb23a69bc, - 0x946a45ab, 0x24801247, 0xb4ed2b8e, 0x26b6a417 + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000002 ); + # elif EXHAUSTIVE_TEST_ORDER == 199 + static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_G_ORDER_199; static const secp256k1_fe secp256k1_fe_const_b = SECP256K1_FE_CONST( - 0x2cca28fa, 0xfc614b80, 0x2a3db42b, 0x00ba00b1, - 0xbea8d943, 0xdace9ab2, 0x9536daea, 0x0074defb + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000004 ); + # else # error No known generator for the specified exhaustive test group order. # endif #else + static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_G; -static const secp256k1_fe secp256k1_fe_const_b = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 7); +static const secp256k1_fe secp256k1_fe_const_b = SECP256K1_FE_CONST( + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000007 +); + #endif +/* End of section generated by sage/gen_exhaustive_groups.sage. */ static void secp256k1_ge_set_gej_zinv(secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zi) { secp256k1_fe zi2; diff --git a/src/modules/recovery/tests_exhaustive_impl.h b/src/modules/recovery/tests_exhaustive_impl.h index ed9386b6..142f7137 100644 --- a/src/modules/recovery/tests_exhaustive_impl.h +++ b/src/modules/recovery/tests_exhaustive_impl.h @@ -43,8 +43,7 @@ void test_exhaustive_recovery_sign(const secp256k1_context *ctx, const secp256k1 (k * (EXHAUSTIVE_TEST_ORDER - s)) % EXHAUSTIVE_TEST_ORDER == (i + r * j) % EXHAUSTIVE_TEST_ORDER); /* The recid's second bit is for conveying overflow (R.x value >= group order). * In the actual secp256k1 this is an astronomically unlikely event, but in the - * small group used here, it will be the case for all points except the ones where - * R.x=1 (which the group is specifically selected to have). + * small group used here, it will almost certainly be the case for all points. * Note that this isn't actually useful; full recovery would need to convey * floor(R.x / group_order), but only one bit is used as that is sufficient * in the real group. */ diff --git a/src/precomputed_ecmult.h b/src/precomputed_ecmult.h index 949b62c8..a4aa83e4 100644 --- a/src/precomputed_ecmult.h +++ b/src/precomputed_ecmult.h @@ -13,7 +13,9 @@ extern "C" { #include "group.h" #if defined(EXHAUSTIVE_TEST_ORDER) -#if EXHAUSTIVE_TEST_ORDER == 13 +# if EXHAUSTIVE_TEST_ORDER == 7 +# define WINDOW_G 3 +# elif EXHAUSTIVE_TEST_ORDER == 13 # define WINDOW_G 4 # elif EXHAUSTIVE_TEST_ORDER == 199 # define WINDOW_G 8 diff --git a/src/scalar_impl.h b/src/scalar_impl.h index 3a57f565..9e72df2e 100644 --- a/src/scalar_impl.h +++ b/src/scalar_impl.h @@ -33,15 +33,18 @@ static int secp256k1_scalar_set_b32_seckey(secp256k1_scalar *r, const unsigned c return (!overflow) & (!secp256k1_scalar_is_zero(r)); } -/* These parameters are generated using sage/gen_exhaustive_groups.sage. */ #if defined(EXHAUSTIVE_TEST_ORDER) -# if EXHAUSTIVE_TEST_ORDER == 13 +/* Begin of section generated by sage/gen_exhaustive_groups.sage. */ +# if EXHAUSTIVE_TEST_ORDER == 7 +# define EXHAUSTIVE_TEST_LAMBDA 2 +# elif EXHAUSTIVE_TEST_ORDER == 13 # define EXHAUSTIVE_TEST_LAMBDA 9 # elif EXHAUSTIVE_TEST_ORDER == 199 # define EXHAUSTIVE_TEST_LAMBDA 92 # else # error No known lambda for the specified exhaustive test group order. # endif +/* End of section generated by sage/gen_exhaustive_groups.sage. */ /** * Find r1 and r2 given k, such that r1 + r2 * lambda == k mod n; unlike in the From ce60785b2654e60b43577dd75996b7020afbfec8 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Tue, 10 Jan 2023 16:23:32 -0500 Subject: [PATCH 17/47] Introduce SECP256K1_B macro for curve b coefficient --- sage/gen_exhaustive_groups.sage | 7 +------ src/group_impl.h | 26 ++++++-------------------- 2 files changed, 7 insertions(+), 26 deletions(-) diff --git a/sage/gen_exhaustive_groups.sage b/sage/gen_exhaustive_groups.sage index 60265809..070bc128 100644 --- a/sage/gen_exhaustive_groups.sage +++ b/sage/gen_exhaustive_groups.sage @@ -96,10 +96,7 @@ def output_generator(g, name): print(")") def output_b(b): - print("static const secp256k1_fe secp256k1_fe_const_b = SECP256K1_FE_CONST(") - print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x," % tuple((int(b) >> (32 * (7 - i))) & 0xffffffff for i in range(4))) - print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x" % tuple((int(b) >> (32 * (7 - i))) & 0xffffffff for i in range(4, 8))) - print(");") + print(f"#define SECP256K1_B {int(b)}") print() print("To be put in src/group_impl.h:") @@ -128,7 +125,6 @@ for f in sorted(solutions.keys()): first = False print() print(f"static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_G_ORDER_{f};") - print("") output_b(b) print() print("# else") @@ -137,7 +133,6 @@ print("# endif") print("#else") print() print("static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_G;") -print("") output_b(7) print() print("#endif") diff --git a/src/group_impl.h b/src/group_impl.h index ed2b50b8..3a57ee8a 100644 --- a/src/group_impl.h +++ b/src/group_impl.h @@ -49,29 +49,17 @@ # if EXHAUSTIVE_TEST_ORDER == 7 static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_G_ORDER_7; - -static const secp256k1_fe secp256k1_fe_const_b = SECP256K1_FE_CONST( - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000006 -); +#define SECP256K1_B 6 # elif EXHAUSTIVE_TEST_ORDER == 13 static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_G_ORDER_13; - -static const secp256k1_fe secp256k1_fe_const_b = SECP256K1_FE_CONST( - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000002 -); +#define SECP256K1_B 2 # elif EXHAUSTIVE_TEST_ORDER == 199 static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_G_ORDER_199; - -static const secp256k1_fe secp256k1_fe_const_b = SECP256K1_FE_CONST( - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000004 -); +#define SECP256K1_B 4 # else # error No known generator for the specified exhaustive test group order. @@ -79,15 +67,13 @@ static const secp256k1_fe secp256k1_fe_const_b = SECP256K1_FE_CONST( #else static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_G; - -static const secp256k1_fe secp256k1_fe_const_b = SECP256K1_FE_CONST( - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000007 -); +#define SECP256K1_B 7 #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; From d6ff738d5bbdf965590fc07efca23b13c0ea3082 Mon Sep 17 00:00:00 2001 From: Russell O'Connor Date: Mon, 16 Jan 2023 22:09:29 -0500 Subject: [PATCH 18/47] Ensure safety of ctz_debruijn implementation. Adding U to the magic constants ensures that we are not mixing unsigned and signed value during multiplication, and ensures that the multiplication will not be subject to integer promotion. The (uint32_t)/(uint64_t) casts ensure the values are properly truncated no matter the size of an int. Prior to this commit, if secp256k1_ctz32_var_debruijn were some how managed to be built on a platform with 64-bit ints, (though this function is specifically only intended to be used on 32-bit platforms) it would perform an out-of-bounds array access. --- src/util.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util.h b/src/util.h index a25ac873..e75c5ad5 100644 --- a/src/util.h +++ b/src/util.h @@ -251,7 +251,7 @@ static SECP256K1_INLINE int secp256k1_ctz32_var_debruijn(uint32_t x) { 0x10, 0x07, 0x0C, 0x1A, 0x1F, 0x17, 0x12, 0x05, 0x15, 0x09, 0x0F, 0x0B, 0x1E, 0x11, 0x08, 0x0E, 0x1D, 0x0D, 0x1C, 0x1B }; - return debruijn[((x & -x) * 0x04D7651F) >> 27]; + return debruijn[(uint32_t)((x & -x) * 0x04D7651FU) >> 27]; } /* Determine the number of trailing zero bits in a (non-zero) 64-bit x. @@ -264,7 +264,7 @@ static SECP256K1_INLINE int secp256k1_ctz64_var_debruijn(uint64_t x) { 63, 52, 6, 26, 37, 40, 33, 47, 61, 45, 43, 21, 23, 58, 17, 10, 51, 25, 36, 32, 60, 20, 57, 16, 50, 31, 19, 15, 30, 14, 13, 12 }; - return debruijn[((x & -x) * 0x022FDD63CC95386D) >> 58]; + return debruijn[(uint64_t)((x & -x) * 0x022FDD63CC95386DU) >> 58]; } /* Determine the number of trailing zero bits in a (non-zero) 32-bit x. */ From 8f51229e0348a1524fed541f334cd4f1726d2685 Mon Sep 17 00:00:00 2001 From: Jonas Nick Date: Wed, 18 Jan 2023 09:02:47 +0000 Subject: [PATCH 19/47] ctime_tests: improve output when CHECKMEM_RUNNING is not defined --- src/ctime_tests.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ctime_tests.c b/src/ctime_tests.c index aaa6f7f4..713eb427 100644 --- a/src/ctime_tests.c +++ b/src/ctime_tests.c @@ -38,7 +38,7 @@ int main(void) { int ret, i; if (!SECP256K1_CHECKMEM_RUNNING()) { - fprintf(stderr, "Unless compiled under msan, this test can only usefully be run inside valgrind.\n"); + fprintf(stderr, "This test can only usefully be run inside valgrind because it was not compiled under msan.\n"); fprintf(stderr, "Usage: libtool --mode=execute valgrind ./ctime_tests\n"); return 1; } From 4b6df5e33e197a50fd7d9bc4c14b8ba8526013b9 Mon Sep 17 00:00:00 2001 From: Tim Ruffing Date: Wed, 7 Dec 2022 14:38:45 +0100 Subject: [PATCH 20/47] contexts: Forbid cloning/destroying secp256k1_context_static --- CHANGELOG.md | 3 ++ include/secp256k1.h | 6 ++- include/secp256k1_preallocated.h | 8 +++- src/secp256k1.c | 28 +++++++++---- src/tests.c | 67 +++++++++++++++++++++++++------- 5 files changed, 88 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3a13a399..7755f61e 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] +#### Changed + - Forbade cloning or destroying `secp256k1_context_static`. Create a new context instead of cloning the static context. (If this change breaks your code, your code is probably wrong.) + ## [0.2.0] - 2022-12-12 #### Added diff --git a/include/secp256k1.h b/include/secp256k1.h index 3d169ecc..a228ef63 100644 --- a/include/secp256k1.h +++ b/include/secp256k1.h @@ -291,8 +291,11 @@ SECP256K1_API secp256k1_context* secp256k1_context_create( * called at most once for every call of this function. If you need to avoid dynamic * memory allocation entirely, see the functions in secp256k1_preallocated.h. * + * Cloning secp256k1_context_static is not possible, and should not be emulated by + * the caller (e.g., using memcpy). Create a new context instead. + * * Returns: a newly created context object. - * Args: ctx: an existing context to copy + * Args: ctx: an existing context to copy (not secp256k1_context_static) */ SECP256K1_API secp256k1_context* secp256k1_context_clone( const secp256k1_context* ctx @@ -310,6 +313,7 @@ SECP256K1_API secp256k1_context* secp256k1_context_clone( * * Args: ctx: an existing context to destroy, constructed using * secp256k1_context_create or secp256k1_context_clone + * (i.e., not secp256k1_context_static). */ SECP256K1_API void secp256k1_context_destroy( secp256k1_context* ctx diff --git a/include/secp256k1_preallocated.h b/include/secp256k1_preallocated.h index ed846f75..ffa96dd3 100644 --- a/include/secp256k1_preallocated.h +++ b/include/secp256k1_preallocated.h @@ -88,8 +88,11 @@ SECP256K1_API size_t secp256k1_context_preallocated_clone_size( * the lifetime of this context object, see the description of * secp256k1_context_preallocated_create for details. * + * Cloning secp256k1_context_static is not possible, and should not be emulated by + * the caller (e.g., using memcpy). Create a new context instead. + * * Returns: a newly created context object. - * Args: ctx: an existing context to copy. + * Args: ctx: an existing context to copy (not secp256k1_context_static). * In: prealloc: a pointer to a rewritable contiguous block of memory of * size at least secp256k1_context_preallocated_size(flags) * bytes, as detailed above. @@ -117,7 +120,8 @@ SECP256K1_API secp256k1_context* secp256k1_context_preallocated_clone( * * Args: ctx: an existing context to destroy, constructed using * secp256k1_context_preallocated_create or - * secp256k1_context_preallocated_clone. + * secp256k1_context_preallocated_clone + * (i.e., not secp256k1_context_static). */ SECP256K1_API void secp256k1_context_preallocated_destroy( secp256k1_context* ctx diff --git a/src/secp256k1.c b/src/secp256k1.c index 6c91a761..3e9e7ccc 100644 --- a/src/secp256k1.c +++ b/src/secp256k1.c @@ -109,9 +109,9 @@ size_t secp256k1_context_preallocated_size(unsigned int flags) { } size_t secp256k1_context_preallocated_clone_size(const secp256k1_context* ctx) { - size_t ret = sizeof(secp256k1_context); VERIFY_CHECK(ctx != NULL); - return ret; + ARG_CHECK(secp256k1_context_is_proper(ctx)); + return sizeof(secp256k1_context); } secp256k1_context* secp256k1_context_preallocated_create(void* prealloc, unsigned int flags) { @@ -152,6 +152,7 @@ secp256k1_context* secp256k1_context_preallocated_clone(const secp256k1_context* secp256k1_context* ret; VERIFY_CHECK(ctx != NULL); ARG_CHECK(prealloc != NULL); + ARG_CHECK(secp256k1_context_is_proper(ctx)); ret = (secp256k1_context*)prealloc; *ret = *ctx; @@ -163,6 +164,8 @@ secp256k1_context* secp256k1_context_clone(const secp256k1_context* ctx) { size_t prealloc_size; VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_context_is_proper(ctx)); + prealloc_size = secp256k1_context_preallocated_clone_size(ctx); ret = (secp256k1_context*)checked_malloc(&ctx->error_callback, prealloc_size); ret = secp256k1_context_preallocated_clone(ctx, ret); @@ -170,17 +173,26 @@ secp256k1_context* secp256k1_context_clone(const secp256k1_context* ctx) { } void secp256k1_context_preallocated_destroy(secp256k1_context* ctx) { - ARG_CHECK_VOID(ctx != secp256k1_context_static); - if (ctx != NULL) { - secp256k1_ecmult_gen_context_clear(&ctx->ecmult_gen_ctx); + ARG_CHECK_VOID(ctx == NULL || secp256k1_context_is_proper(ctx)); + + /* Defined as noop */ + if (ctx == NULL) { + return; } + + secp256k1_ecmult_gen_context_clear(&ctx->ecmult_gen_ctx); } void secp256k1_context_destroy(secp256k1_context* ctx) { - if (ctx != NULL) { - secp256k1_context_preallocated_destroy(ctx); - free(ctx); + ARG_CHECK_VOID(ctx == NULL || secp256k1_context_is_proper(ctx)); + + /* Defined as noop */ + if (ctx == NULL) { + return; } + + secp256k1_context_preallocated_destroy(ctx); + free(ctx); } void secp256k1_context_set_illegal_callback(secp256k1_context* ctx, void (*fun)(const char* message, void* data), const void* data) { diff --git a/src/tests.c b/src/tests.c index 9cc4d176..c33d1dc4 100644 --- a/src/tests.c +++ b/src/tests.c @@ -32,6 +32,18 @@ static int COUNT = 64; static secp256k1_context *CTX = NULL; static secp256k1_context *STATIC_CTX = NULL; +static int all_bytes_equal(const void* s, unsigned char value, size_t n) { + const unsigned char *p = s; + size_t i; + + for (i = 0; i < n; i++) { + if (p[i] != value) { + return 0; + } + } + return 1; +} + static void counting_illegal_callback_fn(const char* str, void* data) { /* Dummy callback function that just counts. */ int32_t *p; @@ -229,20 +241,47 @@ static void run_ec_illegal_argument_tests(void) { secp256k1_context_set_illegal_callback(CTX, NULL, NULL); } -static void run_static_context_tests(void) { - int32_t dummy = 0; - +static void run_static_context_tests(int use_prealloc) { /* Check that deprecated secp256k1_context_no_precomp is an alias to secp256k1_context_static. */ CHECK(secp256k1_context_no_precomp == secp256k1_context_static); - /* check if sizes for cloning are consistent */ - CHECK(secp256k1_context_preallocated_clone_size(STATIC_CTX) >= sizeof(secp256k1_context)); + { + int ecount = 0; + secp256k1_context_set_illegal_callback(STATIC_CTX, counting_illegal_callback_fn, &ecount); + /* Destroying or cloning secp256k1_context_static is not supported. */ + if (use_prealloc) { + CHECK(secp256k1_context_preallocated_clone_size(STATIC_CTX) == 0); + CHECK(ecount == 1); + { + secp256k1_context *my_static_ctx = malloc(sizeof(*STATIC_CTX)); + CHECK(my_static_ctx != NULL); + memset(my_static_ctx, 0x2a, sizeof(*my_static_ctx)); + CHECK(secp256k1_context_preallocated_clone(STATIC_CTX, my_static_ctx) == NULL); + CHECK(all_bytes_equal(my_static_ctx, 0x2a, sizeof(*my_static_ctx))); + CHECK(ecount == 2); + free(my_static_ctx); + } + secp256k1_context_preallocated_destroy(STATIC_CTX); + CHECK(ecount == 3); + } else { + CHECK(secp256k1_context_clone(STATIC_CTX) == NULL); + CHECK(ecount == 1); + secp256k1_context_destroy(STATIC_CTX); + CHECK(ecount == 2); + } + secp256k1_context_set_illegal_callback(STATIC_CTX, NULL, NULL); + } - /* Verify that setting and resetting illegal callback works */ - secp256k1_context_set_illegal_callback(STATIC_CTX, counting_illegal_callback_fn, &dummy); - CHECK(STATIC_CTX->illegal_callback.fn == counting_illegal_callback_fn); - secp256k1_context_set_illegal_callback(STATIC_CTX, NULL, NULL); - CHECK(STATIC_CTX->illegal_callback.fn == secp256k1_default_illegal_callback_fn); + { + /* Verify that setting and resetting illegal callback works */ + int32_t dummy = 0; + secp256k1_context_set_illegal_callback(STATIC_CTX, counting_illegal_callback_fn, &dummy); + CHECK(STATIC_CTX->illegal_callback.fn == counting_illegal_callback_fn); + CHECK(STATIC_CTX->illegal_callback.data == &dummy); + secp256k1_context_set_illegal_callback(STATIC_CTX, NULL, NULL); + CHECK(STATIC_CTX->illegal_callback.fn == secp256k1_default_illegal_callback_fn); + CHECK(STATIC_CTX->illegal_callback.data == NULL); + } } static void run_proper_context_tests(int use_prealloc) { @@ -300,8 +339,10 @@ static void run_proper_context_tests(int use_prealloc) { /* Verify that setting and resetting illegal callback works */ secp256k1_context_set_illegal_callback(my_ctx, counting_illegal_callback_fn, &dummy); CHECK(my_ctx->illegal_callback.fn == counting_illegal_callback_fn); + CHECK(my_ctx->illegal_callback.data == &dummy); secp256k1_context_set_illegal_callback(my_ctx, NULL, NULL); CHECK(my_ctx->illegal_callback.fn == secp256k1_default_illegal_callback_fn); + CHECK(my_ctx->illegal_callback.data == NULL); /*** attempt to use them ***/ random_scalar_order_test(&msg); @@ -327,6 +368,7 @@ static void run_proper_context_tests(int use_prealloc) { } else { secp256k1_context_destroy(my_ctx); } + /* Defined as no-op. */ secp256k1_context_destroy(NULL); secp256k1_context_preallocated_destroy(NULL); @@ -7389,9 +7431,8 @@ int main(int argc, char **argv) { run_selftest_tests(); /* context tests */ - run_proper_context_tests(0); - run_proper_context_tests(1); - run_static_context_tests(); + run_proper_context_tests(0); run_proper_context_tests(1); + run_static_context_tests(0); run_static_context_tests(1); run_deprecated_context_flags_test(); /* scratch tests */ From 61841fc9ee5aa1ffde3ccd512660207034125ebd Mon Sep 17 00:00:00 2001 From: Tim Ruffing Date: Wed, 7 Dec 2022 14:50:14 +0100 Subject: [PATCH 21/47] contexts: Forbid randomizing secp256k1_context_static --- CHANGELOG.md | 1 + include/secp256k1.h | 16 +++++-------- src/secp256k1.c | 2 ++ src/tests.c | 55 +++++++++++++++++++++++++++++++++++++++------ 4 files changed, 57 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7755f61e..62a89f83 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 #### Changed - Forbade cloning or destroying `secp256k1_context_static`. Create a new context instead of cloning the static context. (If this change breaks your code, your code is probably wrong.) + - Forbade randomizing (copies of) `secp256k1_context_static`. Randomizing a copy of `secp256k1_context_static` did not have any effect and did not provide defense-in-depth protection against side-channel attacks. Create a new context if you want to benefit from randomization. ## [0.2.0] - 2022-12-12 diff --git a/include/secp256k1.h b/include/secp256k1.h index a228ef63..3a75b050 100644 --- a/include/secp256k1.h +++ b/include/secp256k1.h @@ -824,10 +824,10 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_mul( /** Randomizes the context to provide enhanced protection against side-channel leakage. * - * Returns: 1: randomization successful (or called on copy of secp256k1_context_static) + * Returns: 1: randomization successful * 0: error - * Args: ctx: pointer to a context object. - * In: seed32: pointer to a 32-byte random seed (NULL resets to initial state) + * Args: ctx: pointer to a context object (not secp256k1_context_static). + * In: seed32: pointer to a 32-byte random seed (NULL resets to initial state). * * While secp256k1 code is written and tested to be constant-time no matter what * secret values are, it is possible that a compiler may output code which is not, @@ -842,21 +842,17 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_mul( * functions that perform computations involving secret keys, e.g., signing and * public key generation. It is possible to call this function more than once on * the same context, and doing so before every few computations involving secret - * keys is recommended as a defense-in-depth measure. + * keys is recommended as a defense-in-depth measure. Randomization of the static + * context secp256k1_context_static is not supported. * * Currently, the random seed is mainly used for blinding multiplications of a * secret scalar with the elliptic curve base point. Multiplications of this * kind are performed by exactly those API functions which are documented to - * require a context that is not the secp256k1_context_static. As a rule of thumb, + * require a context that is not secp256k1_context_static. As a rule of thumb, * these are all functions which take a secret key (or a keypair) as an input. * A notable exception to that rule is the ECDH module, which relies on a different * kind of elliptic curve point multiplication and thus does not benefit from * enhanced protection against side-channel leakage currently. - * - * It is safe to call this function on a copy of secp256k1_context_static in writable - * memory (e.g., obtained via secp256k1_context_clone). In that case, this - * function is guaranteed to return 1, but the call will have no effect because - * the static context (or a copy thereof) is not meant to be randomized. */ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_context_randomize( secp256k1_context* ctx, diff --git a/src/secp256k1.c b/src/secp256k1.c index 3e9e7ccc..7af333ca 100644 --- a/src/secp256k1.c +++ b/src/secp256k1.c @@ -749,6 +749,8 @@ int secp256k1_ec_pubkey_tweak_mul(const secp256k1_context* ctx, secp256k1_pubkey int secp256k1_context_randomize(secp256k1_context* ctx, const unsigned char *seed32) { VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_context_is_proper(ctx)); + if (secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)) { secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, seed32); } diff --git a/src/tests.c b/src/tests.c index c33d1dc4..22bc042b 100644 --- a/src/tests.c +++ b/src/tests.c @@ -247,7 +247,16 @@ static void run_static_context_tests(int use_prealloc) { { int ecount = 0; + unsigned char seed[32] = {0x17}; secp256k1_context_set_illegal_callback(STATIC_CTX, counting_illegal_callback_fn, &ecount); + + /* Randomizing secp256k1_context_static is not supported. */ + CHECK(secp256k1_context_randomize(STATIC_CTX, seed) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_context_randomize(STATIC_CTX, NULL) == 0); + CHECK(ecount == 2); + ecount = 0; + /* Destroying or cloning secp256k1_context_static is not supported. */ if (use_prealloc) { CHECK(secp256k1_context_preallocated_clone_size(STATIC_CTX) == 0); @@ -286,13 +295,18 @@ static void run_static_context_tests(int use_prealloc) { static void run_proper_context_tests(int use_prealloc) { int32_t dummy = 0; - secp256k1_context *my_ctx; + secp256k1_context *my_ctx, *my_ctx_fresh; void *my_ctx_prealloc = NULL; + unsigned char seed[32] = {0x17}; secp256k1_gej pubj; secp256k1_ge pub; secp256k1_scalar msg, key, nonce; secp256k1_scalar sigr, sigs; + + /* Fresh reference context for comparison */ + my_ctx_fresh = secp256k1_context_create(SECP256K1_CONTEXT_NONE); + if (use_prealloc) { my_ctx_prealloc = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE)); CHECK(my_ctx_prealloc != NULL); @@ -301,6 +315,13 @@ static void run_proper_context_tests(int use_prealloc) { my_ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); } + /* Randomize and reset randomization */ + CHECK(context_eq(my_ctx, my_ctx_fresh)); + CHECK(secp256k1_context_randomize(my_ctx, seed) == 1); + CHECK(!context_eq(my_ctx, my_ctx_fresh)); + CHECK(secp256k1_context_randomize(my_ctx, NULL) == 1); + CHECK(context_eq(my_ctx, my_ctx_fresh)); + /* set error callback (to a function that still aborts in case malloc() fails in secp256k1_context_clone() below) */ secp256k1_context_set_error_callback(my_ctx, secp256k1_default_illegal_callback_fn, NULL); CHECK(my_ctx->error_callback.fn != secp256k1_default_error_callback_fn); @@ -315,16 +336,33 @@ static void run_proper_context_tests(int use_prealloc) { if (use_prealloc) { /* clone into a non-preallocated context and then again into a new preallocated one. */ - ctx_tmp = my_ctx; my_ctx = secp256k1_context_clone(my_ctx); secp256k1_context_preallocated_destroy(ctx_tmp); - free(my_ctx_prealloc); my_ctx_prealloc = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE)); CHECK(my_ctx_prealloc != NULL); - ctx_tmp = my_ctx; my_ctx = secp256k1_context_preallocated_clone(my_ctx, my_ctx_prealloc); secp256k1_context_destroy(ctx_tmp); + ctx_tmp = my_ctx; + my_ctx = secp256k1_context_clone(my_ctx); + CHECK(context_eq(ctx_tmp, my_ctx)); + secp256k1_context_preallocated_destroy(ctx_tmp); + + free(my_ctx_prealloc); + my_ctx_prealloc = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE)); + CHECK(my_ctx_prealloc != NULL); + ctx_tmp = my_ctx; + my_ctx = secp256k1_context_preallocated_clone(my_ctx, my_ctx_prealloc); + CHECK(context_eq(ctx_tmp, my_ctx)); + secp256k1_context_destroy(ctx_tmp); } else { /* clone into a preallocated context and then again into a new non-preallocated one. */ void *prealloc_tmp; - prealloc_tmp = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE)); CHECK(prealloc_tmp != NULL); - ctx_tmp = my_ctx; my_ctx = secp256k1_context_preallocated_clone(my_ctx, prealloc_tmp); secp256k1_context_destroy(ctx_tmp); - ctx_tmp = my_ctx; my_ctx = secp256k1_context_clone(my_ctx); secp256k1_context_preallocated_destroy(ctx_tmp); + prealloc_tmp = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE)); + CHECK(prealloc_tmp != NULL); + ctx_tmp = my_ctx; + my_ctx = secp256k1_context_preallocated_clone(my_ctx, prealloc_tmp); + CHECK(context_eq(ctx_tmp, my_ctx)); + secp256k1_context_destroy(ctx_tmp); + + ctx_tmp = my_ctx; + my_ctx = secp256k1_context_clone(my_ctx); + CHECK(context_eq(ctx_tmp, my_ctx)); + secp256k1_context_preallocated_destroy(ctx_tmp); free(prealloc_tmp); } } @@ -335,6 +373,7 @@ static void run_proper_context_tests(int use_prealloc) { /* And that it resets back to default. */ secp256k1_context_set_error_callback(my_ctx, NULL, NULL); CHECK(my_ctx->error_callback.fn == secp256k1_default_error_callback_fn); + CHECK(context_eq(my_ctx, my_ctx_fresh)); /* Verify that setting and resetting illegal callback works */ secp256k1_context_set_illegal_callback(my_ctx, counting_illegal_callback_fn, &dummy); @@ -343,6 +382,7 @@ static void run_proper_context_tests(int use_prealloc) { secp256k1_context_set_illegal_callback(my_ctx, NULL, NULL); CHECK(my_ctx->illegal_callback.fn == secp256k1_default_illegal_callback_fn); CHECK(my_ctx->illegal_callback.data == NULL); + CHECK(context_eq(my_ctx, my_ctx_fresh)); /*** attempt to use them ***/ random_scalar_order_test(&msg); @@ -368,6 +408,7 @@ static void run_proper_context_tests(int use_prealloc) { } else { secp256k1_context_destroy(my_ctx); } + secp256k1_context_destroy(my_ctx_fresh); /* Defined as no-op. */ secp256k1_context_destroy(NULL); From 613626f94c77a484f6acf22a72ab6cd8ddda00cd Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Thu, 19 Jan 2023 09:27:33 +0000 Subject: [PATCH 22/47] Drop no longer used `SECP_TEST_{LIBS,INCLUDE}` variables The last usage of the `SECP_TEST_{LIBS,INCLUDE}` variables was removed in https://github.com/bitcoin-core/secp256k1/pull/983. --- Makefile.am | 6 +++--- configure.ac | 2 -- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/Makefile.am b/Makefile.am index f02ddaf1..c099168f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -103,7 +103,7 @@ noinst_PROGRAMS = if USE_BENCHMARK noinst_PROGRAMS += bench bench_internal bench_ecmult bench_SOURCES = src/bench.c -bench_LDADD = libsecp256k1.la $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB) +bench_LDADD = libsecp256k1.la $(SECP_LIBS) $(COMMON_LIB) bench_CPPFLAGS = $(SECP_CONFIG_DEFINES) bench_internal_SOURCES = src/bench_internal.c bench_internal_LDADD = $(SECP_LIBS) $(COMMON_LIB) $(PRECOMPUTED_LIB) @@ -118,8 +118,8 @@ if USE_TESTS TESTS += noverify_tests noinst_PROGRAMS += noverify_tests noverify_tests_SOURCES = src/tests.c -noverify_tests_CPPFLAGS = $(SECP_INCLUDES) $(SECP_TEST_INCLUDES) $(SECP_CONFIG_DEFINES) -noverify_tests_LDADD = $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB) $(PRECOMPUTED_LIB) +noverify_tests_CPPFLAGS = $(SECP_INCLUDES) $(SECP_CONFIG_DEFINES) +noverify_tests_LDADD = $(SECP_LIBS) $(COMMON_LIB) $(PRECOMPUTED_LIB) noverify_tests_LDFLAGS = -static if !ENABLE_COVERAGE TESTS += tests diff --git a/configure.ac b/configure.ac index cb5d0397..c4f8e481 100644 --- a/configure.ac +++ b/configure.ac @@ -408,8 +408,6 @@ fi AC_CONFIG_FILES([Makefile libsecp256k1.pc]) AC_SUBST(SECP_INCLUDES) AC_SUBST(SECP_LIBS) -AC_SUBST(SECP_TEST_LIBS) -AC_SUBST(SECP_TEST_INCLUDES) AC_SUBST(SECP_CFLAGS) AC_SUBST(SECP_CONFIG_DEFINES) AM_CONDITIONAL([ENABLE_COVERAGE], [test x"$enable_coverage" = x"yes"]) From 2cd4e3c0a976c78c1619fc7456fcc4eaa92897a9 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Thu, 19 Jan 2023 09:43:28 +0000 Subject: [PATCH 23/47] Drop no longer used `SECP_{LIBS,INCLUDE}` variables The last usage of the `SECP_INCLUDE` variable was removed in https://github.com/bitcoin-core/secp256k1/pull/1169. --- Makefile.am | 34 +++++++++++++++++----------------- configure.ac | 2 -- libsecp256k1.pc.in | 1 - 3 files changed, 17 insertions(+), 20 deletions(-) diff --git a/Makefile.am b/Makefile.am index c099168f..122e044c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -76,7 +76,7 @@ noinst_LTLIBRARIES = $(PRECOMPUTED_LIB) libsecp256k1_precomputed_la_SOURCES = src/precomputed_ecmult.c src/precomputed_ecmult_gen.c # We need `-I$(top_srcdir)/src` in VPATH builds if libsecp256k1_precomputed_la_SOURCES have been recreated in the build tree. # This helps users and packagers who insist on recreating the precomputed files (e.g., Gentoo). -libsecp256k1_precomputed_la_CPPFLAGS = -I$(top_srcdir)/src $(SECP_INCLUDES) $(SECP_CONFIG_DEFINES) +libsecp256k1_precomputed_la_CPPFLAGS = -I$(top_srcdir)/src $(SECP_CONFIG_DEFINES) if USE_EXTERNAL_ASM COMMON_LIB = libsecp256k1_common.la @@ -95,22 +95,22 @@ endif endif libsecp256k1_la_SOURCES = src/secp256k1.c -libsecp256k1_la_CPPFLAGS = $(SECP_INCLUDES) $(SECP_CONFIG_DEFINES) -libsecp256k1_la_LIBADD = $(SECP_LIBS) $(COMMON_LIB) $(PRECOMPUTED_LIB) +libsecp256k1_la_CPPFLAGS = $(SECP_CONFIG_DEFINES) +libsecp256k1_la_LIBADD = $(COMMON_LIB) $(PRECOMPUTED_LIB) libsecp256k1_la_LDFLAGS = -no-undefined -version-info $(LIB_VERSION_CURRENT):$(LIB_VERSION_REVISION):$(LIB_VERSION_AGE) noinst_PROGRAMS = if USE_BENCHMARK noinst_PROGRAMS += bench bench_internal bench_ecmult bench_SOURCES = src/bench.c -bench_LDADD = libsecp256k1.la $(SECP_LIBS) $(COMMON_LIB) +bench_LDADD = libsecp256k1.la $(COMMON_LIB) bench_CPPFLAGS = $(SECP_CONFIG_DEFINES) bench_internal_SOURCES = src/bench_internal.c -bench_internal_LDADD = $(SECP_LIBS) $(COMMON_LIB) $(PRECOMPUTED_LIB) -bench_internal_CPPFLAGS = $(SECP_INCLUDES) $(SECP_CONFIG_DEFINES) +bench_internal_LDADD = $(COMMON_LIB) $(PRECOMPUTED_LIB) +bench_internal_CPPFLAGS = $(SECP_CONFIG_DEFINES) bench_ecmult_SOURCES = src/bench_ecmult.c -bench_ecmult_LDADD = $(SECP_LIBS) $(COMMON_LIB) $(PRECOMPUTED_LIB) -bench_ecmult_CPPFLAGS = $(SECP_INCLUDES) $(SECP_CONFIG_DEFINES) +bench_ecmult_LDADD = $(COMMON_LIB) $(PRECOMPUTED_LIB) +bench_ecmult_CPPFLAGS = $(SECP_CONFIG_DEFINES) endif TESTS = @@ -118,8 +118,8 @@ if USE_TESTS TESTS += noverify_tests noinst_PROGRAMS += noverify_tests noverify_tests_SOURCES = src/tests.c -noverify_tests_CPPFLAGS = $(SECP_INCLUDES) $(SECP_CONFIG_DEFINES) -noverify_tests_LDADD = $(SECP_LIBS) $(COMMON_LIB) $(PRECOMPUTED_LIB) +noverify_tests_CPPFLAGS = $(SECP_CONFIG_DEFINES) +noverify_tests_LDADD = $(COMMON_LIB) $(PRECOMPUTED_LIB) noverify_tests_LDFLAGS = -static if !ENABLE_COVERAGE TESTS += tests @@ -134,19 +134,19 @@ endif if USE_CTIME_TESTS noinst_PROGRAMS += ctime_tests ctime_tests_SOURCES = src/ctime_tests.c -ctime_tests_LDADD = libsecp256k1.la $(SECP_LIBS) $(COMMON_LIB) +ctime_tests_LDADD = libsecp256k1.la $(COMMON_LIB) ctime_tests_CPPFLAGS = $(SECP_CONFIG_DEFINES) endif if USE_EXHAUSTIVE_TESTS noinst_PROGRAMS += exhaustive_tests exhaustive_tests_SOURCES = src/tests_exhaustive.c -exhaustive_tests_CPPFLAGS = $(SECP_INCLUDES) $(SECP_CONFIG_DEFINES) +exhaustive_tests_CPPFLAGS = $(SECP_CONFIG_DEFINES) if !ENABLE_COVERAGE exhaustive_tests_CPPFLAGS += -DVERIFY endif # Note: do not include $(PRECOMPUTED_LIB) in exhaustive_tests (it uses runtime-generated tables). -exhaustive_tests_LDADD = $(SECP_LIBS) $(COMMON_LIB) +exhaustive_tests_LDADD = $(COMMON_LIB) exhaustive_tests_LDFLAGS = -static TESTS += exhaustive_tests endif @@ -190,12 +190,12 @@ EXTRA_PROGRAMS = precompute_ecmult precompute_ecmult_gen CLEANFILES = $(EXTRA_PROGRAMS) precompute_ecmult_SOURCES = src/precompute_ecmult.c -precompute_ecmult_CPPFLAGS = $(SECP_INCLUDES) $(SECP_CONFIG_DEFINES) -precompute_ecmult_LDADD = $(SECP_LIBS) $(COMMON_LIB) +precompute_ecmult_CPPFLAGS = $(SECP_CONFIG_DEFINES) +precompute_ecmult_LDADD = $(COMMON_LIB) precompute_ecmult_gen_SOURCES = src/precompute_ecmult_gen.c -precompute_ecmult_gen_CPPFLAGS = $(SECP_INCLUDES) $(SECP_CONFIG_DEFINES) -precompute_ecmult_gen_LDADD = $(SECP_LIBS) $(COMMON_LIB) +precompute_ecmult_gen_CPPFLAGS = $(SECP_CONFIG_DEFINES) +precompute_ecmult_gen_LDADD = $(COMMON_LIB) # See Automake manual, Section "Errors with distclean". # We don't list any dependencies for the prebuilt files here because diff --git a/configure.ac b/configure.ac index c4f8e481..9249ae03 100644 --- a/configure.ac +++ b/configure.ac @@ -406,8 +406,6 @@ fi ### AC_CONFIG_FILES([Makefile libsecp256k1.pc]) -AC_SUBST(SECP_INCLUDES) -AC_SUBST(SECP_LIBS) AC_SUBST(SECP_CFLAGS) AC_SUBST(SECP_CONFIG_DEFINES) AM_CONDITIONAL([ENABLE_COVERAGE], [test x"$enable_coverage" = x"yes"]) diff --git a/libsecp256k1.pc.in b/libsecp256k1.pc.in index 694e98ee..0fb6f48a 100644 --- a/libsecp256k1.pc.in +++ b/libsecp256k1.pc.in @@ -9,5 +9,4 @@ URL: https://github.com/bitcoin-core/secp256k1 Version: @PACKAGE_VERSION@ Cflags: -I${includedir} Libs: -L${libdir} -lsecp256k1 -Libs.private: @SECP_LIBS@ From e39d954f118a29db2c33e9a9a507053fff5573ed Mon Sep 17 00:00:00 2001 From: Tim Ruffing Date: Tue, 17 Jan 2023 12:23:38 +0100 Subject: [PATCH 24/47] tests: Add CHECK_ILLEGAL(_VOID) macros and use in static ctx tests --- src/tests.c | 46 ++++++++++++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/src/tests.c b/src/tests.c index 22bc042b..bc5b7cb1 100644 --- a/src/tests.c +++ b/src/tests.c @@ -44,11 +44,31 @@ static int all_bytes_equal(const void* s, unsigned char value, size_t n) { return 1; } +/* 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 + * + * For checking functions that use ARG_CHECK_VOID */ +#define CHECK_ILLEGAL_VOID(ctx, expr_or_stmt) do { \ + int32_t _calls_to_illegal_callback = 0; \ + secp256k1_callback _saved_illegal_cb = ctx->illegal_callback; \ + secp256k1_context_set_illegal_callback(ctx, \ + counting_illegal_callback_fn, &_calls_to_illegal_callback); \ + { expr_or_stmt; } \ + ctx->illegal_callback = _saved_illegal_cb; \ + CHECK(_calls_to_illegal_callback == 1); \ +} while(0); + +/* CHECK that expr calls the illegal callback of ctx exactly once and that expr == 0 + * + * For checking functions that use ARG_CHECK */ +#define CHECK_ILLEGAL(ctx, expr) CHECK_ILLEGAL_VOID(ctx, CHECK((expr) == 0)) + static void counting_illegal_callback_fn(const char* str, void* data) { /* Dummy callback function that just counts. */ int32_t *p; (void)str; p = data; + CHECK(*p != INT32_MAX); (*p)++; } @@ -57,6 +77,7 @@ static void uncounting_illegal_callback_fn(const char* str, void* data) { int32_t *p; (void)str; p = data; + CHECK(*p != INT32_MIN); (*p)--; } @@ -246,39 +267,28 @@ static void run_static_context_tests(int use_prealloc) { CHECK(secp256k1_context_no_precomp == secp256k1_context_static); { - int ecount = 0; unsigned char seed[32] = {0x17}; - secp256k1_context_set_illegal_callback(STATIC_CTX, counting_illegal_callback_fn, &ecount); /* Randomizing secp256k1_context_static is not supported. */ - CHECK(secp256k1_context_randomize(STATIC_CTX, seed) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_context_randomize(STATIC_CTX, NULL) == 0); - CHECK(ecount == 2); - ecount = 0; + CHECK_ILLEGAL(STATIC_CTX, secp256k1_context_randomize(STATIC_CTX, seed)); + CHECK_ILLEGAL(STATIC_CTX, secp256k1_context_randomize(STATIC_CTX, NULL)); /* Destroying or cloning secp256k1_context_static is not supported. */ if (use_prealloc) { - CHECK(secp256k1_context_preallocated_clone_size(STATIC_CTX) == 0); - CHECK(ecount == 1); + CHECK_ILLEGAL(STATIC_CTX, secp256k1_context_preallocated_clone_size(STATIC_CTX)); { secp256k1_context *my_static_ctx = malloc(sizeof(*STATIC_CTX)); CHECK(my_static_ctx != NULL); memset(my_static_ctx, 0x2a, sizeof(*my_static_ctx)); - CHECK(secp256k1_context_preallocated_clone(STATIC_CTX, my_static_ctx) == NULL); + CHECK_ILLEGAL(STATIC_CTX, secp256k1_context_preallocated_clone(STATIC_CTX, my_static_ctx)); CHECK(all_bytes_equal(my_static_ctx, 0x2a, sizeof(*my_static_ctx))); - CHECK(ecount == 2); free(my_static_ctx); } - secp256k1_context_preallocated_destroy(STATIC_CTX); - CHECK(ecount == 3); + CHECK_ILLEGAL_VOID(STATIC_CTX, secp256k1_context_preallocated_destroy(STATIC_CTX)); } else { - CHECK(secp256k1_context_clone(STATIC_CTX) == NULL); - CHECK(ecount == 1); - secp256k1_context_destroy(STATIC_CTX); - CHECK(ecount == 2); + CHECK_ILLEGAL(STATIC_CTX, secp256k1_context_clone(STATIC_CTX)); + CHECK_ILLEGAL_VOID(STATIC_CTX, secp256k1_context_destroy(STATIC_CTX)); } - secp256k1_context_set_illegal_callback(STATIC_CTX, NULL, NULL); } { From 620ba3d74bed3095cec7cd8877c8ce14cbf5e329 Mon Sep 17 00:00:00 2001 From: Jonas Nick Date: Fri, 9 Dec 2022 22:31:15 +0000 Subject: [PATCH 25/47] benchmarks: fix bench_scalar_split scalar_split_lambda requires that the input pointer is different to both output pointers. Without this fix, the internal benchmarks crash when compiled with -DVERIFY. This was introduced in commit 362bb25608dbcd724a07dd5170c4ebe081c3dd84 (which requires configuring with --enable-endomorphism to exhibit the crash). --- src/bench_internal.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/bench_internal.c b/src/bench_internal.c index fd794a1c..e1ef14fd 100644 --- a/src/bench_internal.c +++ b/src/bench_internal.c @@ -110,10 +110,11 @@ static void bench_scalar_mul(void* arg, int iters) { static void bench_scalar_split(void* arg, int iters) { int i, j = 0; bench_inv *data = (bench_inv*)arg; + secp256k1_scalar tmp; for (i = 0; i < iters; i++) { - secp256k1_scalar_split_lambda(&data->scalar[0], &data->scalar[1], &data->scalar[0]); - j += secp256k1_scalar_add(&data->scalar[0], &data->scalar[0], &data->scalar[1]); + secp256k1_scalar_split_lambda(&tmp, &data->scalar[1], &data->scalar[0]); + j += secp256k1_scalar_add(&data->scalar[0], &tmp, &data->scalar[1]); } CHECK(j <= iters); } From 7f49aa7f2dca595ac8b58d0268dc46a9dfff1e38 Mon Sep 17 00:00:00 2001 From: Jonas Nick Date: Fri, 9 Dec 2022 23:04:57 +0000 Subject: [PATCH 26/47] ci: add test job with -DVERIFY This detects benchmarks that crash when VERIFY is defined. --- .cirrus.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.cirrus.yml b/.cirrus.yml index ac682e50..a4182e1d 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -81,6 +81,7 @@ task: - env: {WIDEMUL: int128, ECDH: yes, SCHNORRSIG: yes} - env: {WIDEMUL: int128, ASM: x86_64} - env: { RECOVERY: yes, SCHNORRSIG: yes} + - env: {CTIMETESTS: no, RECOVERY: yes, ECDH: yes, SCHNORRSIG: yes, CPPFLAGS: -DVERIFY} - env: {BUILD: distcheck, WITH_VALGRIND: no, CTIMETESTS: no, BENCH: no} - env: {CPPFLAGS: -DDETERMINISTIC} - env: {CFLAGS: -O0, CTIMETESTS: no} From eb6bebaee3947f8bca46816fa6bf6182085f1b56 Mon Sep 17 00:00:00 2001 From: Jonas Nick Date: Wed, 4 Jan 2023 11:21:04 +0000 Subject: [PATCH 27/47] scalar: restrict split_lambda args, improve doc and VERIFY_CHECKs VERIFY_CHECK(r1 != r2) is added because otherwise the verify_scalar_split fails. --- src/scalar.h | 7 ++++--- src/scalar_impl.h | 8 ++++++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/scalar.h b/src/scalar.h index b9cb6b05..63c0d646 100644 --- a/src/scalar.h +++ b/src/scalar.h @@ -88,9 +88,10 @@ static int secp256k1_scalar_eq(const secp256k1_scalar *a, const secp256k1_scalar /** Find r1 and r2 such that r1+r2*2^128 = k. */ static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *k); -/** Find r1 and r2 such that r1+r2*lambda = k, - * where r1 and r2 or their negations are maximum 128 bits long (see secp256k1_ge_mul_lambda). */ -static void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *k); +/** Find r1 and r2 such that r1+r2*lambda = k, where r1 and r2 or their + * negations are maximum 128 bits long (see secp256k1_ge_mul_lambda). It is + * required that r1, r2, and k all point to different objects. */ +static void secp256k1_scalar_split_lambda(secp256k1_scalar * SECP256K1_RESTRICT r1, secp256k1_scalar * SECP256K1_RESTRICT r2, const secp256k1_scalar * SECP256K1_RESTRICT k); /** Multiply a and b (without taking the modulus!), divide by 2**shift, and round to the nearest integer. Shift must be at least 256. */ static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b, unsigned int shift); diff --git a/src/scalar_impl.h b/src/scalar_impl.h index 9e72df2e..bed7f95f 100644 --- a/src/scalar_impl.h +++ b/src/scalar_impl.h @@ -52,7 +52,10 @@ static int secp256k1_scalar_set_b32_seckey(secp256k1_scalar *r, const unsigned c * nontrivial to get full test coverage for the exhaustive tests. We therefore * (arbitrarily) set r2 = k + 5 (mod n) and r1 = k - r2 * lambda (mod n). */ -static void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *k) { +static void secp256k1_scalar_split_lambda(secp256k1_scalar * SECP256K1_RESTRICT r1, secp256k1_scalar * SECP256K1_RESTRICT r2, const secp256k1_scalar * SECP256K1_RESTRICT k) { + VERIFY_CHECK(r1 != k); + VERIFY_CHECK(r2 != k); + VERIFY_CHECK(r1 != r2); *r2 = (*k + 5) % EXHAUSTIVE_TEST_ORDER; *r1 = (*k + (EXHAUSTIVE_TEST_ORDER - *r2) * EXHAUSTIVE_TEST_LAMBDA) % EXHAUSTIVE_TEST_ORDER; } @@ -119,7 +122,7 @@ static void secp256k1_scalar_split_lambda_verify(const secp256k1_scalar *r1, con * * See proof below. */ -static void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *k) { +static void secp256k1_scalar_split_lambda(secp256k1_scalar * SECP256K1_RESTRICT r1, secp256k1_scalar * SECP256K1_RESTRICT r2, const secp256k1_scalar * SECP256K1_RESTRICT k) { secp256k1_scalar c1, c2; static const secp256k1_scalar minus_b1 = SECP256K1_SCALAR_CONST( 0x00000000UL, 0x00000000UL, 0x00000000UL, 0x00000000UL, @@ -139,6 +142,7 @@ static void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar ); VERIFY_CHECK(r1 != k); VERIFY_CHECK(r2 != k); + VERIFY_CHECK(r1 != r2); /* these _var calls are constant time since the shift amount is constant */ secp256k1_scalar_mul_shift_var(&c1, k, &g1, 384); secp256k1_scalar_mul_shift_var(&c2, k, &g2, 384); From 0ecf3188515e46b4da5580b4b9805d2cb927eb91 Mon Sep 17 00:00:00 2001 From: Tim Ruffing Date: Fri, 27 Jan 2023 22:38:45 +0100 Subject: [PATCH 28/47] ci: Use remote pull/merge ref instead of local git merge The merge strategy on the remote may be different than the local one. This may cause local merges to be different or fail completely. Fix this by using the result of the remote merge. (copied from bitcoin/bitcoin@fad7281d7842f337932cf44e703fdd631230ddd6) --- .cirrus.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index ac682e50..3c24cde1 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -53,11 +53,11 @@ cat_logs_snippet: &CAT_LOGS merge_base_script_snippet: &MERGE_BASE merge_base_script: - - if [ "$CIRRUS_PR" = "" ]; then exit 0; fi - - git fetch $CIRRUS_REPO_CLONE_URL $CIRRUS_BASE_BRANCH - git config --global user.email "ci@ci.ci" - git config --global user.name "ci" - - git merge FETCH_HEAD # Merge base to detect silent merge conflicts + - if [ "$CIRRUS_PR" = "" ]; then exit 0; fi + - git fetch $CIRRUS_REPO_CLONE_URL "pull/${CIRRUS_PR}/merge" + - git checkout FETCH_HEAD # Use merged changes to detect silent merge conflicts linux_container_snippet: &LINUX_CONTAINER container: From c2415866c7a6769cb29e3db6c5312c1255b37083 Mon Sep 17 00:00:00 2001 From: Tim Ruffing Date: Fri, 27 Jan 2023 22:44:11 +0100 Subject: [PATCH 29/47] ci: Don't fetch git history (copied from bitcoin/bitcoin@faa65f12fc137231c0333330f670847473650028) --- .cirrus.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.cirrus.yml b/.cirrus.yml index 3c24cde1..bed135c3 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -1,4 +1,6 @@ env: + ### cirrus config + CIRRUS_CLONE_DEPTH: 1 ### compiler options HOST: WRAPPER_CMD: @@ -56,7 +58,7 @@ merge_base_script_snippet: &MERGE_BASE - git config --global user.email "ci@ci.ci" - git config --global user.name "ci" - if [ "$CIRRUS_PR" = "" ]; then exit 0; fi - - git fetch $CIRRUS_REPO_CLONE_URL "pull/${CIRRUS_PR}/merge" + - git fetch --depth=1 $CIRRUS_REPO_CLONE_URL "pull/${CIRRUS_PR}/merge" - git checkout FETCH_HEAD # Use merged changes to detect silent merge conflicts linux_container_snippet: &LINUX_CONTAINER From 9b7d18669dc2410bde7690d9b04d90b3dc3e25ce Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Sat, 28 Jan 2023 07:26:10 +0000 Subject: [PATCH 30/47] Drop no longer used Autoheader macros --- configure.ac | 3 --- 1 file changed, 3 deletions(-) diff --git a/configure.ac b/configure.ac index 9249ae03..aa79e9d7 100644 --- a/configure.ac +++ b/configure.ac @@ -22,9 +22,6 @@ AC_INIT([libsecp256k1],m4_join([.], _PKG_VERSION_MAJOR, _PKG_VERSION_MINOR, _PKG AC_CONFIG_AUX_DIR([build-aux]) AC_CONFIG_MACRO_DIR([build-aux/m4]) AC_CANONICAL_HOST -AH_TOP([#ifndef LIBSECP256K1_CONFIG_H]) -AH_TOP([#define LIBSECP256K1_CONFIG_H]) -AH_BOTTOM([#endif /*LIBSECP256K1_CONFIG_H*/]) # Require Automake 1.11.2 for AM_PROG_AR AM_INIT_AUTOMAKE([1.11.2 foreign subdir-objects]) From 9b60e3148d8c19562c8c3805bd0cdc55933e912c Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Mon, 30 Jan 2023 16:29:46 +0000 Subject: [PATCH 31/47] ci: Do not set git's `user.{email,name}` config options git's `user.{email,name}` config options have been no longer required since 0ecf3188515e46b4da5580b4b9805d2cb927eb91. --- .cirrus.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index d7787d34..48b09df5 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -55,8 +55,6 @@ cat_logs_snippet: &CAT_LOGS merge_base_script_snippet: &MERGE_BASE merge_base_script: - - git config --global user.email "ci@ci.ci" - - git config --global user.name "ci" - if [ "$CIRRUS_PR" = "" ]; then exit 0; fi - git fetch --depth=1 $CIRRUS_REPO_CLONE_URL "pull/${CIRRUS_PR}/merge" - git checkout FETCH_HEAD # Use merged changes to detect silent merge conflicts From ef39721cccec344983f09180bcf9c443d491f7cb Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Mon, 30 Jan 2023 22:42:39 +0000 Subject: [PATCH 32/47] Do not link `bench` and `ctime_tests` to `COMMON_LIB` The `bench` and `ctime_tests` are users of the library, they should only be linked to the library, not the objects it was built from. --- Makefile.am | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile.am b/Makefile.am index 122e044c..48ee2fcf 100644 --- a/Makefile.am +++ b/Makefile.am @@ -103,7 +103,7 @@ noinst_PROGRAMS = if USE_BENCHMARK noinst_PROGRAMS += bench bench_internal bench_ecmult bench_SOURCES = src/bench.c -bench_LDADD = libsecp256k1.la $(COMMON_LIB) +bench_LDADD = libsecp256k1.la bench_CPPFLAGS = $(SECP_CONFIG_DEFINES) bench_internal_SOURCES = src/bench_internal.c bench_internal_LDADD = $(COMMON_LIB) $(PRECOMPUTED_LIB) @@ -134,7 +134,7 @@ endif if USE_CTIME_TESTS noinst_PROGRAMS += ctime_tests ctime_tests_SOURCES = src/ctime_tests.c -ctime_tests_LDADD = libsecp256k1.la $(COMMON_LIB) +ctime_tests_LDADD = libsecp256k1.la ctime_tests_CPPFLAGS = $(SECP_CONFIG_DEFINES) endif From 8c7e0fc1de048be98a1f1bc75557671afc14beaa Mon Sep 17 00:00:00 2001 From: Tim Ruffing Date: Thu, 2 Feb 2023 14:56:58 +0100 Subject: [PATCH 33/47] build: Add -Wreserved-identifier supported by clang This warns on certain identifiers reserved by the C standard, namely * identifiers that begin with an underscore followed by an uppercase letter, and * identifiers in the global namespace that begin with an underscore. We had used such identifiers in the past for macros in include guards, and we should make sure that we don't reintroduce such identifiers going forward. Note that C reserves more identifiers for "future library directions", e.g., identifiers that begin with "str" followed by a lowercase letter. But even the C standards committee has decided that this is somewhat silly and adopted a proposal [1] for C23 that removes the restriction that programs using these identifiers have UB. Instead, these identifiers are now "potentially reserved", which is not a normative restriction but simply an informative warning that the identifiers may become fully reserved in the future. [1] https://www.open-std.org/jtc1/sc22/WG14/www/docs/n2625.pdf --- configure.ac | 1 + 1 file changed, 1 insertion(+) diff --git a/configure.ac b/configure.ac index aa79e9d7..fc51db2b 100644 --- a/configure.ac +++ b/configure.ac @@ -102,6 +102,7 @@ AC_DEFUN([SECP_TRY_APPEND_DEFAULT_CFLAGS], [ SECP_TRY_APPEND_CFLAGS([-Wcast-align], $1) # GCC >= 2.95 SECP_TRY_APPEND_CFLAGS([-Wcast-align=strict], $1) # GCC >= 8.0 SECP_TRY_APPEND_CFLAGS([-Wconditional-uninitialized], $1) # Clang >= 3.0 only + SECP_TRY_APPEND_CFLAGS([-Wreserved-identifier], $1) # Clang >= 13.0 only SECP_TRY_APPEND_CFLAGS([-fvisibility=hidden], $1) # GCC >= 4.0 CFLAGS="$SECP_TRY_APPEND_DEFAULT_CFLAGS_saved_CFLAGS" From 914276e4d27a5f21407744d8016b6d0789e676b1 Mon Sep 17 00:00:00 2001 From: Tim Ruffing Date: Sat, 28 Jan 2023 10:15:33 +0100 Subject: [PATCH 34/47] build: Add SECP256K1_API_VAR to fix importing variables from DLLs This fixes a build issue with MSVC. While MSVC imports *functions* from DLLs automatically when building a consumer of the DLL, it does not import *variables* automatically. In these cases, we need an explicit __declspec(dllimport). This commit simply changes our logic to what the libtool manual suggests, which has a very comprehensive writeup on the topic. Note that in particular, this solution is carefully designed not to break static linking. However, as described in the libtool manual, statically linking the library with MSVC will output warning LNK4217. This is still the best solution overall, because the warning is merely a cosmetic issue. --- include/secp256k1.h | 39 ++++++++++++++++++++-------------- include/secp256k1_ecdh.h | 4 ++-- include/secp256k1_schnorrsig.h | 2 +- 3 files changed, 26 insertions(+), 19 deletions(-) diff --git a/include/secp256k1.h b/include/secp256k1.h index 3a75b050..325f35eb 100644 --- a/include/secp256k1.h +++ b/include/secp256k1.h @@ -145,21 +145,28 @@ typedef int (*secp256k1_nonce_function)( # define SECP256K1_NO_BUILD #endif -/** At secp256k1 build-time DLL_EXPORT is defined when building objects destined - * for a shared library, but not for those intended for static libraries. - */ - -#ifndef SECP256K1_API -# if defined(_WIN32) -# if defined(SECP256K1_BUILD) && defined(DLL_EXPORT) -# define SECP256K1_API __declspec(dllexport) -# else -# define SECP256K1_API +/* Symbol visibility. See libtool manual, section "Windows DLLs". */ +#if defined(_WIN32) && !defined(__GNUC__) +# ifdef SECP256K1_BUILD +# ifdef DLL_EXPORT +# define SECP256K1_API __declspec (dllexport) +# define SECP256K1_API_VAR extern __declspec (dllexport) # endif -# elif defined(__GNUC__) && (__GNUC__ >= 4) && defined(SECP256K1_BUILD) -# define SECP256K1_API __attribute__ ((visibility ("default"))) +# elif defined _MSC_VER +# define SECP256K1_API +# define SECP256K1_API_VAR extern __declspec (dllimport) +# elif defined DLL_EXPORT +# define SECP256K1_API __declspec (dllimport) +# define SECP256K1_API_VAR extern __declspec (dllimport) +# endif +#endif +#ifndef SECP256K1_API +# if defined(__GNUC__) && (__GNUC__ >= 4) && defined(SECP256K1_BUILD) +# define SECP256K1_API __attribute__ ((visibility ("default"))) +# define SECP256K1_API_VAR extern __attribute__ ((visibility ("default"))) # else # define SECP256K1_API +# define SECP256K1_API_VAR extern # endif #endif @@ -231,10 +238,10 @@ typedef int (*secp256k1_nonce_function)( * * It is highly recommended to call secp256k1_selftest before using this context. */ -SECP256K1_API extern const secp256k1_context *secp256k1_context_static; +SECP256K1_API_VAR const secp256k1_context *secp256k1_context_static; /** Deprecated alias for secp256k1_context_static. */ -SECP256K1_API extern const secp256k1_context *secp256k1_context_no_precomp +SECP256K1_API_VAR const secp256k1_context *secp256k1_context_no_precomp SECP256K1_DEPRECATED("Use secp256k1_context_static instead"); /** Perform basic self tests (to be used in conjunction with secp256k1_context_static) @@ -631,10 +638,10 @@ SECP256K1_API int secp256k1_ecdsa_signature_normalize( * If a data pointer is passed, it is assumed to be a pointer to 32 bytes of * extra entropy. */ -SECP256K1_API extern const secp256k1_nonce_function secp256k1_nonce_function_rfc6979; +SECP256K1_API_VAR const secp256k1_nonce_function secp256k1_nonce_function_rfc6979; /** A default safe nonce generation function (currently equal to secp256k1_nonce_function_rfc6979). */ -SECP256K1_API extern const secp256k1_nonce_function secp256k1_nonce_function_default; +SECP256K1_API_VAR const secp256k1_nonce_function secp256k1_nonce_function_default; /** Create an ECDSA signature. * diff --git a/include/secp256k1_ecdh.h b/include/secp256k1_ecdh.h index c8577984..625061b2 100644 --- a/include/secp256k1_ecdh.h +++ b/include/secp256k1_ecdh.h @@ -27,11 +27,11 @@ typedef int (*secp256k1_ecdh_hash_function)( /** An implementation of SHA256 hash function that applies to compressed public key. * Populates the output parameter with 32 bytes. */ -SECP256K1_API extern const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_sha256; +SECP256K1_API_VAR const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_sha256; /** A default ECDH hash function (currently equal to secp256k1_ecdh_hash_function_sha256). * Populates the output parameter with 32 bytes. */ -SECP256K1_API extern const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_default; +SECP256K1_API_VAR const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_default; /** Compute an EC Diffie-Hellman secret in constant time * diff --git a/include/secp256k1_schnorrsig.h b/include/secp256k1_schnorrsig.h index e579e1b1..4cd2d982 100644 --- a/include/secp256k1_schnorrsig.h +++ b/include/secp256k1_schnorrsig.h @@ -61,7 +61,7 @@ typedef int (*secp256k1_nonce_function_hardened)( * Therefore, to create BIP-340 compliant signatures, algo must be set to * "BIP0340/nonce" and algolen to 13. */ -SECP256K1_API extern const secp256k1_nonce_function_hardened secp256k1_nonce_function_bip340; +SECP256K1_API_VAR const secp256k1_nonce_function_hardened secp256k1_nonce_function_bip340; /** Data structure that contains additional arguments for schnorrsig_sign_custom. * From 739c53b19a22bd8cd251e25ea286089664a2f0eb Mon Sep 17 00:00:00 2001 From: Tim Ruffing Date: Mon, 6 Feb 2023 21:31:47 +0100 Subject: [PATCH 35/47] examples: Extend sig examples by call that uses static context Besides improving the examples, this makes sure that the examples import a variable (instead of a function), namely the static context, from the library. This is helpful when testing MSVC builds, because the MSVC linker tends to be awkward when importing variables. --- examples/ecdsa.c | 12 ++++++++++-- examples/schnorr.c | 11 ++++++++++- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/examples/ecdsa.c b/examples/ecdsa.c index 7e4f1b13..01088e31 100644 --- a/examples/ecdsa.c +++ b/examples/ecdsa.c @@ -34,7 +34,7 @@ int main(void) { unsigned char compressed_pubkey[33]; unsigned char serialized_signature[64]; size_t len; - int is_signature_valid; + int is_signature_valid, is_signature_valid2; int return_val; secp256k1_pubkey pubkey; secp256k1_ecdsa_signature sig; @@ -116,10 +116,18 @@ int main(void) { printf("Signature: "); print_hex(serialized_signature, sizeof(serialized_signature)); - /* This will clear everything from the context and free the memory */ secp256k1_context_destroy(ctx); + /* Bonus example: if all we need is signature verification (and no key + generation or signing), we don't need to use a context created via + secp256k1_context_create(). We can simply use the static (i.e., global) + context secp256k1_context_static. See its description in + include/secp256k1.h for details. */ + is_signature_valid2 = secp256k1_ecdsa_verify(secp256k1_context_static, + &sig, msg_hash, &pubkey); + assert(is_signature_valid2 == is_signature_valid); + /* It's best practice to try to clear secrets from memory after using them. * This is done because some bugs can allow an attacker to leak memory, for * example through "out of bounds" array access (see Heartbleed), Or the OS diff --git a/examples/schnorr.c b/examples/schnorr.c index 207c45c4..535b59a1 100644 --- a/examples/schnorr.c +++ b/examples/schnorr.c @@ -26,7 +26,7 @@ int main(void) { unsigned char auxiliary_rand[32]; unsigned char serialized_pubkey[32]; unsigned char signature[64]; - int is_signature_valid; + int is_signature_valid, is_signature_valid2; int return_val; secp256k1_xonly_pubkey pubkey; secp256k1_keypair keypair; @@ -135,6 +135,15 @@ int main(void) { /* This will clear everything from the context and free the memory */ secp256k1_context_destroy(ctx); + /* Bonus example: if all we need is signature verification (and no key + generation or signing), we don't need to use a context created via + secp256k1_context_create(). We can simply use the static (i.e., global) + context secp256k1_context_static. See its description in + include/secp256k1.h for details. */ + is_signature_valid2 = secp256k1_schnorrsig_verify(secp256k1_context_static, + signature, msg_hash, 32, &pubkey); + assert(is_signature_valid2 == is_signature_valid); + /* It's best practice to try to clear secrets from memory after using them. * This is done because some bugs can allow an attacker to leak memory, for * example through "out of bounds" array access (see Heartbleed), Or the OS From 9a5a611a21fcdf7bf2dab30964cd0208d8cdf444 Mon Sep 17 00:00:00 2001 From: Tim Ruffing Date: Mon, 6 Feb 2023 21:34:50 +0100 Subject: [PATCH 36/47] build: Suppress stupid MSVC linker warning ... and use correct format to pass linker flags --- .cirrus.yml | 2 +- configure.ac | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/.cirrus.yml b/.cirrus.yml index 48b09df5..bbfbf716 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -258,7 +258,7 @@ task: # Set non-essential options that affect the CLI messages here. # (They depend on the user's taste, so we don't want to set them automatically in configure.ac.) CFLAGS: -nologo -diagnostics:caret - LDFLAGS: -XCClinker -nologo -XCClinker -diagnostics:caret + LDFLAGS: -Xlinker -Xlinker -Xlinker -nologo matrix: - name: "x86_64 (MSVC): Windows (Debian stable, Wine)" - name: "x86_64 (MSVC): Windows (Debian stable, Wine, int128_struct)" diff --git a/configure.ac b/configure.ac index fc51db2b..ec0738d0 100644 --- a/configure.ac +++ b/configure.ac @@ -115,6 +115,12 @@ AC_DEFUN([SECP_TRY_APPEND_DEFAULT_CFLAGS], [ 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.) + # Unfortunately, libtool tries to be too clever and strips "-Xlinker arg" + # into "arg", so this will be " -Xlinker -ignore:4217" after stripping. + LDFLAGS="-Xlinker -Xlinker -Xlinker -ignore:4217 $LDFLAGS" fi ]) SECP_TRY_APPEND_DEFAULT_CFLAGS(SECP_CFLAGS) From e4330341bd648e93b60fe70c631e311a98bce549 Mon Sep 17 00:00:00 2001 From: Tim Ruffing Date: Sat, 28 Jan 2023 09:22:24 +0100 Subject: [PATCH 37/47] ci: Shutdown wineserver whenever CI script exits Before: CI times out when a wine task fails. After: Wine tasks exit properly when they fail. --- ci/cirrus.sh | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ci/cirrus.sh b/ci/cirrus.sh index e1ca35e3..8495c392 100755 --- a/ci/cirrus.sh +++ b/ci/cirrus.sh @@ -34,6 +34,8 @@ print_environment # This speeds up jobs with many invocations of wine (e.g., ./configure with MSVC) tremendously. case "$WRAPPER_CMD" in *wine*) + # Make sure to shutdown wineserver whenever we exit. + trap "wineserver -k || true" EXIT INT HUP # This is apparently only reliable when we run a dummy command such as "hh.exe" afterwards. wineserver -p && wine hh.exe ;; @@ -111,9 +113,6 @@ then make precomp fi -# Shutdown wineserver again -wineserver -k || true - # Check that no repo files have been modified by the build. # (This fails for example if the precomp files need to be updated in the repo.) git diff --exit-code From 5fffb2c7af5d33223d819283f1a561889a8210d9 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Sat, 10 Dec 2022 15:13:43 -0500 Subject: [PATCH 38/47] Make secp256k1_i128_check_pow2 support -(2^n) --- src/int128.h | 4 ++-- src/int128_native_impl.h | 5 +++-- src/int128_struct_impl.h | 9 +++++---- src/modinv64_impl.h | 2 +- src/tests.c | 38 ++++++++++++++++++++++++++++++++------ 5 files changed, 43 insertions(+), 15 deletions(-) diff --git a/src/int128.h b/src/int128.h index 8c1c061a..5355fbfa 100644 --- a/src/int128.h +++ b/src/int128.h @@ -80,10 +80,10 @@ static SECP256K1_INLINE void secp256k1_i128_from_i64(secp256k1_int128 *r, int64_ /* Compare two 128-bit values for equality. */ static SECP256K1_INLINE int secp256k1_i128_eq_var(const secp256k1_int128 *a, const secp256k1_int128 *b); -/* Tests if r is equal to 2^n. +/* Tests if r is equal to sign*2^n (sign must be 1 or -1). * n must be strictly less than 127. */ -static SECP256K1_INLINE int secp256k1_i128_check_pow2(const secp256k1_int128 *r, unsigned int n); +static SECP256K1_INLINE int secp256k1_i128_check_pow2(const secp256k1_int128 *r, unsigned int n, int sign); #endif diff --git a/src/int128_native_impl.h b/src/int128_native_impl.h index 30c26f2d..996e542c 100644 --- a/src/int128_native_impl.h +++ b/src/int128_native_impl.h @@ -84,9 +84,10 @@ static SECP256K1_INLINE int secp256k1_i128_eq_var(const secp256k1_int128 *a, con return *a == *b; } -static SECP256K1_INLINE int secp256k1_i128_check_pow2(const secp256k1_int128 *r, unsigned int n) { +static SECP256K1_INLINE int secp256k1_i128_check_pow2(const secp256k1_int128 *r, unsigned int n, int sign) { VERIFY_CHECK(n < 127); - return (*r == (int128_t)1 << n); + VERIFY_CHECK(sign == 1 || sign == -1); + return (*r == (int128_t)((uint128_t)sign << n)); } #endif diff --git a/src/int128_struct_impl.h b/src/int128_struct_impl.h index 298a7bb1..2eb337cb 100644 --- a/src/int128_struct_impl.h +++ b/src/int128_struct_impl.h @@ -189,10 +189,11 @@ static SECP256K1_INLINE int secp256k1_i128_eq_var(const secp256k1_int128 *a, con return a->hi == b->hi && a->lo == b->lo; } -static SECP256K1_INLINE int secp256k1_i128_check_pow2(const secp256k1_int128 *r, unsigned int n) { - VERIFY_CHECK(n < 127); - return n >= 64 ? r->hi == (uint64_t)1 << (n - 64) && r->lo == 0 - : r->hi == 0 && r->lo == (uint64_t)1 << n; +static SECP256K1_INLINE int secp256k1_i128_check_pow2(const secp256k1_int128 *r, unsigned int n, int sign) { + VERIFY_CHECK(n < 127); + VERIFY_CHECK(sign == 1 || sign == -1); + return n >= 64 ? r->hi == (uint64_t)sign << (n - 64) && r->lo == 0 + : r->hi == (uint64_t)((sign - 1) >> 1) && r->lo == (uint64_t)sign << n; } #endif diff --git a/src/modinv64_impl.h b/src/modinv64_impl.h index 2b5463a3..d193844a 100644 --- a/src/modinv64_impl.h +++ b/src/modinv64_impl.h @@ -75,7 +75,7 @@ static int secp256k1_modinv64_mul_cmp_62(const secp256k1_modinv64_signed62 *a, i static int secp256k1_modinv64_det_check_pow2(const secp256k1_modinv64_trans2x2 *t, unsigned int n) { secp256k1_int128 a; secp256k1_i128_det(&a, t->u, t->v, t->q, t->r); - return secp256k1_i128_check_pow2(&a, n); + return secp256k1_i128_check_pow2(&a, n, 1); } #endif diff --git a/src/tests.c b/src/tests.c index bc5b7cb1..dadac4c4 100644 --- a/src/tests.c +++ b/src/tests.c @@ -2022,30 +2022,56 @@ static void run_int128_test_case(void) { } CHECK(secp256k1_i128_eq_var(&swa, &swz) == expect); } - /* test secp256k1_i128_check_pow2 */ + /* test secp256k1_i128_check_pow2 (sign == 1) */ { int expect = (uc & 1); int pos = ub % 127; if (expect) { - /* If expect==1, set swz to exactly (2 << pos). */ + /* If expect==1, set swz to exactly 2^pos. */ uint64_t hi = 0; uint64_t lo = 0; - if (pos & 64) { + if (pos >= 64) { hi = (((uint64_t)1) << (pos & 63)); } else { lo = (((uint64_t)1) << (pos & 63)); } secp256k1_i128_load(&swz, hi, lo); } else { - /* If expect==0, set swz = swa, but update expect=1 if swa happens to equal (2 << pos). */ - if (pos & 64) { + /* If expect==0, set swz = swa, but update expect=1 if swa happens to equal 2^pos. */ + if (pos >= 64) { if ((v[1] == (((uint64_t)1) << (pos & 63))) && v[0] == 0) expect = 1; } else { if ((v[0] == (((uint64_t)1) << (pos & 63))) && v[1] == 0) expect = 1; } swz = swa; } - CHECK(secp256k1_i128_check_pow2(&swz, pos) == expect); + CHECK(secp256k1_i128_check_pow2(&swz, pos, 1) == expect); + } + /* test secp256k1_i128_check_pow2 (sign == -1) */ + { + int expect = (uc & 1); + int pos = ub % 127; + if (expect) { + /* If expect==1, set swz to exactly -2^pos. */ + uint64_t hi = ~(uint64_t)0; + uint64_t lo = ~(uint64_t)0; + if (pos >= 64) { + hi <<= (pos & 63); + lo = 0; + } else { + lo <<= (pos & 63); + } + secp256k1_i128_load(&swz, hi, lo); + } else { + /* If expect==0, set swz = swa, but update expect=1 if swa happens to equal -2^pos. */ + if (pos >= 64) { + if ((v[1] == ((~(uint64_t)0) << (pos & 63))) && v[0] == 0) expect = 1; + } else { + if ((v[0] == ((~(uint64_t)0) << (pos & 63))) && v[1] == ~(uint64_t)0) expect = 1; + } + swz = swa; + } + CHECK(secp256k1_i128_check_pow2(&swz, pos, -1) == expect); } } From 04c6c1b18162e3dc00d9be5098ee1ccbcb2e78d9 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Sat, 10 Dec 2022 15:22:32 -0500 Subject: [PATCH 39/47] Make secp256k1_modinv64_det_check_pow2 support abs val --- src/modinv64_impl.h | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/modinv64_impl.h b/src/modinv64_impl.h index d193844a..86cf62f1 100644 --- a/src/modinv64_impl.h +++ b/src/modinv64_impl.h @@ -71,11 +71,13 @@ static int secp256k1_modinv64_mul_cmp_62(const secp256k1_modinv64_signed62 *a, i return 0; } -/* Check if the determinant of t is equal to 1 << n. */ -static int secp256k1_modinv64_det_check_pow2(const secp256k1_modinv64_trans2x2 *t, unsigned int n) { +/* Check if the determinant of t is equal to 1 << n. If abs, check if |det t| == 1 << n. */ +static int secp256k1_modinv64_det_check_pow2(const secp256k1_modinv64_trans2x2 *t, unsigned int n, int abs) { secp256k1_int128 a; secp256k1_i128_det(&a, t->u, t->v, t->q, t->r); - return secp256k1_i128_check_pow2(&a, n, 1); + if (secp256k1_i128_check_pow2(&a, n, 1)) return 1; + if (abs && secp256k1_i128_check_pow2(&a, n, -1)) return 1; + return 0; } #endif @@ -218,7 +220,7 @@ static int64_t secp256k1_modinv64_divsteps_59(int64_t zeta, uint64_t f0, uint64_ * aggregate of 59 of them will have determinant 2^59. Multiplying with the initial * 8*identity (which has determinant 2^6) means the overall outputs has determinant * 2^65. */ - VERIFY_CHECK(secp256k1_modinv64_det_check_pow2(t, 65)); + VERIFY_CHECK(secp256k1_modinv64_det_check_pow2(t, 65, 0)); #endif return zeta; } @@ -301,7 +303,7 @@ static int64_t secp256k1_modinv64_divsteps_62_var(int64_t eta, uint64_t f0, uint * does not change the gcd of f and g, apart from adding a power-of-2 factor to it (which * will be divided out again). As each divstep's individual matrix has determinant 2, the * aggregate of 62 of them will have determinant 2^62. */ - VERIFY_CHECK(secp256k1_modinv64_det_check_pow2(t, 62)); + VERIFY_CHECK(secp256k1_modinv64_det_check_pow2(t, 62, 0)); #endif return eta; } From 1de2a01c2b22dc8216393ad0471382beaffef525 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Sat, 11 Sep 2021 10:39:00 -0400 Subject: [PATCH 40/47] Native jacobi symbol algorithm This introduces variants of the divsteps-based GCD algorithm used for modular inverses to compute Jacobi symbols. Changes compared to the normal vartime divsteps: * Only positive matrices are used, guaranteeing that f and g remain positive. * An additional jac variable is updated to track sign changes during matrix computation. * There is (so far) no proof that this algorithm terminates within reasonable amount of time for every input, but experimentally it appears to almost always need less than 900 iterations. To account for that, only a bounded number of iterations is performed (1500), after which failure is returned. In VERIFY mode a lower iteration count is used to make sure that callers exercise their fallback. * The algorithm converges to f=g=gcd(f0,g0) rather than g=0. To keep this test simple, the end condition is f=1, which won't be reached if started with non-coprime or g=0 inputs. Because of that we only support coprime non-zero inputs. --- src/modinv32.h | 5 ++ src/modinv32_impl.h | 182 ++++++++++++++++++++++++++++++++++++++++---- src/modinv64.h | 5 ++ src/modinv64_impl.h | 164 ++++++++++++++++++++++++++++++++++++++- src/tests.c | 44 ++++++++++- 5 files changed, 381 insertions(+), 19 deletions(-) diff --git a/src/modinv32.h b/src/modinv32.h index d1e6e23c..846c642f 100644 --- a/src/modinv32.h +++ b/src/modinv32.h @@ -35,4 +35,9 @@ static void secp256k1_modinv32_var(secp256k1_modinv32_signed30 *x, const secp256 /* Same as secp256k1_modinv32_var, but constant time in x (not in the modulus). */ static void secp256k1_modinv32(secp256k1_modinv32_signed30 *x, const secp256k1_modinv32_modinfo *modinfo); +/* Compute the Jacobi symbol for (x | modinfo->modulus). x must be coprime with modulus (and thus + * cannot be 0, as modulus >= 3). All limbs of x must be non-negative. Returns 0 if the result + * cannot be computed. */ +static int secp256k1_jacobi32_maybe_var(const secp256k1_modinv32_signed30 *x, const secp256k1_modinv32_modinfo *modinfo); + #endif /* SECP256K1_MODINV32_H */ diff --git a/src/modinv32_impl.h b/src/modinv32_impl.h index 661c5fc0..028a5701 100644 --- a/src/modinv32_impl.h +++ b/src/modinv32_impl.h @@ -232,6 +232,21 @@ static int32_t secp256k1_modinv32_divsteps_30(int32_t zeta, uint32_t f0, uint32_ return zeta; } +/* inv256[i] = -(2*i+1)^-1 (mod 256) */ +static const uint8_t secp256k1_modinv32_inv256[128] = { + 0xFF, 0x55, 0x33, 0x49, 0xC7, 0x5D, 0x3B, 0x11, 0x0F, 0xE5, 0xC3, 0x59, + 0xD7, 0xED, 0xCB, 0x21, 0x1F, 0x75, 0x53, 0x69, 0xE7, 0x7D, 0x5B, 0x31, + 0x2F, 0x05, 0xE3, 0x79, 0xF7, 0x0D, 0xEB, 0x41, 0x3F, 0x95, 0x73, 0x89, + 0x07, 0x9D, 0x7B, 0x51, 0x4F, 0x25, 0x03, 0x99, 0x17, 0x2D, 0x0B, 0x61, + 0x5F, 0xB5, 0x93, 0xA9, 0x27, 0xBD, 0x9B, 0x71, 0x6F, 0x45, 0x23, 0xB9, + 0x37, 0x4D, 0x2B, 0x81, 0x7F, 0xD5, 0xB3, 0xC9, 0x47, 0xDD, 0xBB, 0x91, + 0x8F, 0x65, 0x43, 0xD9, 0x57, 0x6D, 0x4B, 0xA1, 0x9F, 0xF5, 0xD3, 0xE9, + 0x67, 0xFD, 0xDB, 0xB1, 0xAF, 0x85, 0x63, 0xF9, 0x77, 0x8D, 0x6B, 0xC1, + 0xBF, 0x15, 0xF3, 0x09, 0x87, 0x1D, 0xFB, 0xD1, 0xCF, 0xA5, 0x83, 0x19, + 0x97, 0xAD, 0x8B, 0xE1, 0xDF, 0x35, 0x13, 0x29, 0xA7, 0x3D, 0x1B, 0xF1, + 0xEF, 0xC5, 0xA3, 0x39, 0xB7, 0xCD, 0xAB, 0x01 +}; + /* Compute the transition matrix and eta for 30 divsteps (variable time). * * Input: eta: initial eta @@ -243,21 +258,6 @@ static int32_t secp256k1_modinv32_divsteps_30(int32_t zeta, uint32_t f0, uint32_ * Implements the divsteps_n_matrix_var function from the explanation. */ static int32_t secp256k1_modinv32_divsteps_30_var(int32_t eta, uint32_t f0, uint32_t g0, secp256k1_modinv32_trans2x2 *t) { - /* inv256[i] = -(2*i+1)^-1 (mod 256) */ - static const uint8_t inv256[128] = { - 0xFF, 0x55, 0x33, 0x49, 0xC7, 0x5D, 0x3B, 0x11, 0x0F, 0xE5, 0xC3, 0x59, - 0xD7, 0xED, 0xCB, 0x21, 0x1F, 0x75, 0x53, 0x69, 0xE7, 0x7D, 0x5B, 0x31, - 0x2F, 0x05, 0xE3, 0x79, 0xF7, 0x0D, 0xEB, 0x41, 0x3F, 0x95, 0x73, 0x89, - 0x07, 0x9D, 0x7B, 0x51, 0x4F, 0x25, 0x03, 0x99, 0x17, 0x2D, 0x0B, 0x61, - 0x5F, 0xB5, 0x93, 0xA9, 0x27, 0xBD, 0x9B, 0x71, 0x6F, 0x45, 0x23, 0xB9, - 0x37, 0x4D, 0x2B, 0x81, 0x7F, 0xD5, 0xB3, 0xC9, 0x47, 0xDD, 0xBB, 0x91, - 0x8F, 0x65, 0x43, 0xD9, 0x57, 0x6D, 0x4B, 0xA1, 0x9F, 0xF5, 0xD3, 0xE9, - 0x67, 0xFD, 0xDB, 0xB1, 0xAF, 0x85, 0x63, 0xF9, 0x77, 0x8D, 0x6B, 0xC1, - 0xBF, 0x15, 0xF3, 0x09, 0x87, 0x1D, 0xFB, 0xD1, 0xCF, 0xA5, 0x83, 0x19, - 0x97, 0xAD, 0x8B, 0xE1, 0xDF, 0x35, 0x13, 0x29, 0xA7, 0x3D, 0x1B, 0xF1, - 0xEF, 0xC5, 0xA3, 0x39, 0xB7, 0xCD, 0xAB, 0x01 - }; - /* Transformation matrix; see comments in secp256k1_modinv32_divsteps_30. */ uint32_t u = 1, v = 0, q = 0, r = 1; uint32_t f = f0, g = g0, m; @@ -297,7 +297,7 @@ static int32_t secp256k1_modinv32_divsteps_30_var(int32_t eta, uint32_t f0, uint VERIFY_CHECK(limit > 0 && limit <= 30); m = (UINT32_MAX >> (32 - limit)) & 255U; /* Find what multiple of f must be added to g to cancel its bottom min(limit, 8) bits. */ - w = (g * inv256[(f >> 1) & 127]) & m; + w = (g * secp256k1_modinv32_inv256[(f >> 1) & 127]) & m; /* Do so. */ g += f * w; q += u * w; @@ -317,6 +317,86 @@ static int32_t secp256k1_modinv32_divsteps_30_var(int32_t eta, uint32_t f0, uint return eta; } +/* Compute the transition matrix and eta for 30 posdivsteps (variable time, eta=-delta), and keeps track + * of the Jacobi symbol along the way. f0 and g0 must be f and g mod 2^32 rather than 2^30, because + * Jacobi tracking requires knowing (f mod 8) rather than just (f mod 2). + * + * Input: eta: initial eta + * f0: bottom limb of initial f + * g0: bottom limb of initial g + * Output: t: transition matrix + * Input/Output: (*jacp & 1) is bitflipped if and only if the Jacobi symbol of (f | g) changes sign + * by applying the returned transformation matrix to it. The other bits of *jacp may + * change, but are meaningless. + * Return: final eta + */ +static int32_t secp256k1_modinv32_posdivsteps_30_var(int32_t eta, uint32_t f0, uint32_t g0, secp256k1_modinv32_trans2x2 *t, int *jacp) { + /* Transformation matrix. */ + uint32_t u = 1, v = 0, q = 0, r = 1; + uint32_t f = f0, g = g0, m; + uint16_t w; + int i = 30, limit, zeros; + int jac = *jacp; + + for (;;) { + /* Use a sentinel bit to count zeros only up to i. */ + zeros = secp256k1_ctz32_var(g | (UINT32_MAX << i)); + /* Perform zeros divsteps at once; they all just divide g by two. */ + g >>= zeros; + u <<= zeros; + v <<= zeros; + eta -= zeros; + i -= zeros; + /* Update the bottom bit of jac: when dividing g by an odd power of 2, + * if (f mod 8) is 3 or 5, the Jacobi symbol changes sign. */ + jac ^= (zeros & ((f >> 1) ^ (f >> 2))); + /* We're done once we've done 30 posdivsteps. */ + if (i == 0) break; + VERIFY_CHECK((f & 1) == 1); + VERIFY_CHECK((g & 1) == 1); + VERIFY_CHECK((u * f0 + v * g0) == f << (30 - i)); + VERIFY_CHECK((q * f0 + r * g0) == g << (30 - i)); + /* If eta is negative, negate it and replace f,g with g,f. */ + if (eta < 0) { + uint32_t tmp; + eta = -eta; + /* Update bottom bit of jac: when swapping f and g, the Jacobi symbol changes sign + * if both f and g are 3 mod 4. */ + jac ^= ((f & g) >> 1); + tmp = f; f = g; g = tmp; + tmp = u; u = q; q = tmp; + tmp = v; v = r; r = tmp; + } + /* eta is now >= 0. In what follows we're going to cancel out the bottom bits of g. No more + * than i can be cancelled out (as we'd be done before that point), and no more than eta+1 + * can be done as its sign will flip once that happens. */ + limit = ((int)eta + 1) > i ? i : ((int)eta + 1); + /* m is a mask for the bottom min(limit, 8) bits (our table only supports 8 bits). */ + VERIFY_CHECK(limit > 0 && limit <= 30); + m = (UINT32_MAX >> (32 - limit)) & 255U; + /* Find what multiple of f must be added to g to cancel its bottom min(limit, 8) bits. */ + w = (g * secp256k1_modinv32_inv256[(f >> 1) & 127]) & m; + /* Do so. */ + g += f * w; + q += u * w; + r += v * w; + VERIFY_CHECK((g & m) == 0); + } + /* Return data in t and return value. */ + t->u = (int32_t)u; + t->v = (int32_t)v; + t->q = (int32_t)q; + t->r = (int32_t)r; + /* The determinant of t must be a power of two. This guarantees that multiplication with t + * does not change the gcd of f and g, apart from adding a power-of-2 factor to it (which + * will be divided out again). As each divstep's individual matrix has determinant 2 or -2, + * the aggregate of 30 of them will have determinant 2^30 or -2^30. */ + VERIFY_CHECK((int64_t)t->u * t->r - (int64_t)t->v * t->q == ((int64_t)1) << 30 || + (int64_t)t->u * t->r - (int64_t)t->v * t->q == -(((int64_t)1) << 30)); + *jacp = jac; + return eta; +} + /* Compute (t/2^30) * [d, e] mod modulus, where t is a transition matrix for 30 divsteps. * * On input and output, d and e are in range (-2*modulus,modulus). All output limbs will be in range @@ -584,4 +664,74 @@ static void secp256k1_modinv32_var(secp256k1_modinv32_signed30 *x, const secp256 *x = d; } +/* Do up to 50 iterations of 30 posdivsteps (up to 1500 steps; more is extremely rare) each until f=1. + * In VERIFY mode use a lower number of iterations (750, close to the median 756), so failure actually occurs. */ +#ifdef VERIFY +#define JACOBI32_ITERATIONS 25 +#else +#define JACOBI32_ITERATIONS 50 +#endif + +/* Compute the Jacobi symbol of x modulo modinfo->modulus (variable time). gcd(x,modulus) must be 1. */ +static int secp256k1_jacobi32_maybe_var(const secp256k1_modinv32_signed30 *x, const secp256k1_modinv32_modinfo *modinfo) { + /* Start with f=modulus, g=x, eta=-1. */ + secp256k1_modinv32_signed30 f = modinfo->modulus; + secp256k1_modinv32_signed30 g = *x; + int j, len = 9; + int32_t eta = -1; /* eta = -delta; delta is initially 1 */ + int32_t cond, fn, gn; + int jac = 0; + int count; + + /* The input limbs must all be non-negative. */ + VERIFY_CHECK(g.v[0] >= 0 && g.v[1] >= 0 && g.v[2] >= 0 && g.v[3] >= 0 && g.v[4] >= 0 && g.v[5] >= 0 && g.v[6] >= 0 && g.v[7] >= 0 && g.v[8] >= 0); + + /* If x > 0, then if the loop below converges, it converges to f=g=gcd(x,modulus). Since we + * require that gcd(x,modulus)=1 and modulus>=3, x cannot be 0. Thus, we must reach f=1 (or + * time out). */ + VERIFY_CHECK((g.v[0] | g.v[1] | g.v[2] | g.v[3] | g.v[4] | g.v[5] | g.v[6] | g.v[7] | g.v[8]) != 0); + + for (count = 0; count < JACOBI32_ITERATIONS; ++count) { + /* Compute transition matrix and new eta after 30 posdivsteps. */ + secp256k1_modinv32_trans2x2 t; + eta = secp256k1_modinv32_posdivsteps_30_var(eta, f.v[0] | ((uint32_t)f.v[1] << 30), g.v[0] | ((uint32_t)g.v[1] << 30), &t, &jac); + /* Update f,g using that transition matrix. */ +#ifdef VERIFY + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 0) > 0); /* f > 0 */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 0) > 0); /* g > 0 */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */ +#endif + secp256k1_modinv32_update_fg_30_var(len, &f, &g, &t); + /* If the bottom limb of f is 1, there is a chance that f=1. */ + if (f.v[0] == 1) { + cond = 0; + /* Check if the other limbs are also 0. */ + for (j = 1; j < len; ++j) { + cond |= f.v[j]; + } + /* If so, we're done. If f=1, the Jacobi symbol (g | f)=1. */ + if (cond == 0) return 1 - 2*(jac & 1); + } + + /* Determine if len>1 and limb (len-1) of both f and g is 0. */ + fn = f.v[len - 1]; + gn = g.v[len - 1]; + cond = ((int32_t)len - 2) >> 31; + cond |= fn; + cond |= gn; + /* If so, reduce length. */ + if (cond == 0) --len; +#ifdef VERIFY + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 0) > 0); /* f > 0 */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 0) > 0); /* g > 0 */ + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */ +#endif + } + + /* The loop failed to converge to f=g after 1500 iterations. Return 0, indicating unknown result. */ + return 0; +} + #endif /* SECP256K1_MODINV32_IMPL_H */ diff --git a/src/modinv64.h b/src/modinv64.h index 1d69f14f..f4208e6c 100644 --- a/src/modinv64.h +++ b/src/modinv64.h @@ -39,4 +39,9 @@ static void secp256k1_modinv64_var(secp256k1_modinv64_signed62 *x, const secp256 /* Same as secp256k1_modinv64_var, but constant time in x (not in the modulus). */ static void secp256k1_modinv64(secp256k1_modinv64_signed62 *x, const secp256k1_modinv64_modinfo *modinfo); +/* Compute the Jacobi symbol for (x | modinfo->modulus). x must be coprime with modulus (and thus + * cannot be 0, as modulus >= 3). All limbs of x must be non-negative. Returns 0 if the result + * cannot be computed. */ +static int secp256k1_jacobi64_maybe_var(const secp256k1_modinv64_signed62 *x, const secp256k1_modinv64_modinfo *modinfo); + #endif /* SECP256K1_MODINV64_H */ diff --git a/src/modinv64_impl.h b/src/modinv64_impl.h index 86cf62f1..df9aedff 100644 --- a/src/modinv64_impl.h +++ b/src/modinv64_impl.h @@ -268,7 +268,7 @@ static int64_t secp256k1_modinv64_divsteps_62_var(int64_t eta, uint64_t f0, uint tmp = v; v = r; r = -tmp; /* Use a formula to cancel out up to 6 bits of g. Also, no more than i can be cancelled * out (as we'd be done before that point), and no more than eta+1 can be done as its - * will flip again once that happens. */ + * sign will flip again once that happens. */ limit = ((int)eta + 1) > i ? i : ((int)eta + 1); VERIFY_CHECK(limit > 0 && limit <= 62); /* m is a mask for the bottom min(limit, 6) bits. */ @@ -308,6 +308,98 @@ static int64_t secp256k1_modinv64_divsteps_62_var(int64_t eta, uint64_t f0, uint return eta; } +/* Compute the transition matrix and eta for 62 posdivsteps (variable time, eta=-delta), and keeps track + * of the Jacobi symbol along the way. f0 and g0 must be f and g mod 2^64 rather than 2^62, because + * Jacobi tracking requires knowing (f mod 8) rather than just (f mod 2). + * + * Input: eta: initial eta + * f0: bottom limb of initial f + * g0: bottom limb of initial g + * Output: t: transition matrix + * Input/Output: (*jacp & 1) is bitflipped if and only if the Jacobi symbol of (f | g) changes sign + * by applying the returned transformation matrix to it. The other bits of *jacp may + * change, but are meaningless. + * Return: final eta + */ +static int64_t secp256k1_modinv64_posdivsteps_62_var(int64_t eta, uint64_t f0, uint64_t g0, secp256k1_modinv64_trans2x2 *t, int *jacp) { + /* Transformation matrix; see comments in secp256k1_modinv64_divsteps_62. */ + uint64_t u = 1, v = 0, q = 0, r = 1; + uint64_t f = f0, g = g0, m; + uint32_t w; + int i = 62, limit, zeros; + int jac = *jacp; + + for (;;) { + /* Use a sentinel bit to count zeros only up to i. */ + zeros = secp256k1_ctz64_var(g | (UINT64_MAX << i)); + /* Perform zeros divsteps at once; they all just divide g by two. */ + g >>= zeros; + u <<= zeros; + v <<= zeros; + eta -= zeros; + i -= zeros; + /* Update the bottom bit of jac: when dividing g by an odd power of 2, + * if (f mod 8) is 3 or 5, the Jacobi symbol changes sign. */ + jac ^= (zeros & ((f >> 1) ^ (f >> 2))); + /* We're done once we've done 62 posdivsteps. */ + if (i == 0) break; + VERIFY_CHECK((f & 1) == 1); + VERIFY_CHECK((g & 1) == 1); + VERIFY_CHECK((u * f0 + v * g0) == f << (62 - i)); + VERIFY_CHECK((q * f0 + r * g0) == g << (62 - i)); + /* If eta is negative, negate it and replace f,g with g,f. */ + if (eta < 0) { + uint64_t tmp; + eta = -eta; + tmp = f; f = g; g = tmp; + tmp = u; u = q; q = tmp; + tmp = v; v = r; r = tmp; + /* Update bottom bit of jac: when swapping f and g, the Jacobi symbol changes sign + * if both f and g are 3 mod 4. */ + jac ^= ((f & g) >> 1); + /* Use a formula to cancel out up to 6 bits of g. Also, no more than i can be cancelled + * out (as we'd be done before that point), and no more than eta+1 can be done as its + * sign will flip again once that happens. */ + limit = ((int)eta + 1) > i ? i : ((int)eta + 1); + VERIFY_CHECK(limit > 0 && limit <= 62); + /* m is a mask for the bottom min(limit, 6) bits. */ + m = (UINT64_MAX >> (64 - limit)) & 63U; + /* Find what multiple of f must be added to g to cancel its bottom min(limit, 6) + * bits. */ + w = (f * g * (f * f - 2)) & m; + } else { + /* In this branch, use a simpler formula that only lets us cancel up to 4 bits of g, as + * eta tends to be smaller here. */ + limit = ((int)eta + 1) > i ? i : ((int)eta + 1); + VERIFY_CHECK(limit > 0 && limit <= 62); + /* m is a mask for the bottom min(limit, 4) bits. */ + m = (UINT64_MAX >> (64 - limit)) & 15U; + /* Find what multiple of f must be added to g to cancel its bottom min(limit, 4) + * bits. */ + w = f + (((f + 1) & 4) << 1); + w = (-w * g) & m; + } + g += f * w; + q += u * w; + r += v * w; + VERIFY_CHECK((g & m) == 0); + } + /* Return data in t and return value. */ + t->u = (int64_t)u; + t->v = (int64_t)v; + t->q = (int64_t)q; + t->r = (int64_t)r; +#ifdef VERIFY + /* The determinant of t must be a power of two. This guarantees that multiplication with t + * does not change the gcd of f and g, apart from adding a power-of-2 factor to it (which + * will be divided out again). As each divstep's individual matrix has determinant 2 or -2, + * the aggregate of 62 of them will have determinant 2^62 or -2^62. */ + VERIFY_CHECK(secp256k1_modinv64_det_check_pow2(t, 62, 1)); +#endif + *jacp = jac; + return eta; +} + /* Compute (t/2^62) * [d, e] mod modulus, where t is a transition matrix scaled by 2^62. * * On input and output, d and e are in range (-2*modulus,modulus). All output limbs will be in range @@ -628,4 +720,74 @@ static void secp256k1_modinv64_var(secp256k1_modinv64_signed62 *x, const secp256 *x = d; } +/* Do up to 25 iterations of 62 posdivsteps (up to 1550 steps; more is extremely rare) each until f=1. + * In VERIFY mode use a lower number of iterations (744, close to the median 756), so failure actually occurs. */ +#ifdef VERIFY +#define JACOBI64_ITERATIONS 12 +#else +#define JACOBI64_ITERATIONS 25 +#endif + +/* Compute the Jacobi symbol of x modulo modinfo->modulus (variable time). gcd(x,modulus) must be 1. */ +static int secp256k1_jacobi64_maybe_var(const secp256k1_modinv64_signed62 *x, const secp256k1_modinv64_modinfo *modinfo) { + /* Start with f=modulus, g=x, eta=-1. */ + secp256k1_modinv64_signed62 f = modinfo->modulus; + secp256k1_modinv64_signed62 g = *x; + int j, len = 5; + int64_t eta = -1; /* eta = -delta; delta is initially 1 */ + int64_t cond, fn, gn; + int jac = 0; + int count; + + /* The input limbs must all be non-negative. */ + VERIFY_CHECK(g.v[0] >= 0 && g.v[1] >= 0 && g.v[2] >= 0 && g.v[3] >= 0 && g.v[4] >= 0); + + /* If x > 0, then if the loop below converges, it converges to f=g=gcd(x,modulus). Since we + * require that gcd(x,modulus)=1 and modulus>=3, x cannot be 0. Thus, we must reach f=1 (or + * time out). */ + VERIFY_CHECK((g.v[0] | g.v[1] | g.v[2] | g.v[3] | g.v[4]) != 0); + + for (count = 0; count < JACOBI64_ITERATIONS; ++count) { + /* Compute transition matrix and new eta after 62 posdivsteps. */ + secp256k1_modinv64_trans2x2 t; + eta = secp256k1_modinv64_posdivsteps_62_var(eta, f.v[0] | ((uint64_t)f.v[1] << 62), g.v[0] | ((uint64_t)g.v[1] << 62), &t, &jac); + /* Update f,g using that transition matrix. */ +#ifdef VERIFY + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 0) > 0); /* f > 0 */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 0) > 0); /* g > 0 */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */ +#endif + secp256k1_modinv64_update_fg_62_var(len, &f, &g, &t); + /* If the bottom limb of f is 1, there is a chance that f=1. */ + if (f.v[0] == 1) { + cond = 0; + /* Check if the other limbs are also 0. */ + for (j = 1; j < len; ++j) { + cond |= f.v[j]; + } + /* If so, we're done. When f=1, the Jacobi symbol (g | f)=1. */ + if (cond == 0) return 1 - 2*(jac & 1); + } + + /* Determine if len>1 and limb (len-1) of both f and g is 0. */ + fn = f.v[len - 1]; + gn = g.v[len - 1]; + cond = ((int64_t)len - 2) >> 63; + cond |= fn; + cond |= gn; + /* If so, reduce length. */ + if (cond == 0) --len; +#ifdef VERIFY + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 0) > 0); /* f > 0 */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 0) > 0); /* g > 0 */ + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */ +#endif + } + + /* The loop failed to converge to f=g after 1550 iterations. Return 0, indicating unknown result. */ + return 0; +} + #endif /* SECP256K1_MODINV64_IMPL_H */ diff --git a/src/tests.c b/src/tests.c index dadac4c4..9ee6c7b6 100644 --- a/src/tests.c +++ b/src/tests.c @@ -1022,12 +1022,32 @@ static void test_modinv32_uint16(uint16_t* out, const uint16_t* in, const uint16 uint16_to_signed30(&x, in); nonzero = (x.v[0] | x.v[1] | x.v[2] | x.v[3] | x.v[4] | x.v[5] | x.v[6] | x.v[7] | x.v[8]) != 0; uint16_to_signed30(&m.modulus, mod); - mutate_sign_signed30(&m.modulus); /* compute 1/modulus mod 2^30 */ m.modulus_inv30 = modinv2p64(m.modulus.v[0]) & 0x3fffffff; CHECK(((m.modulus_inv30 * m.modulus.v[0]) & 0x3fffffff) == 1); + /* Test secp256k1_jacobi32_maybe_var. */ + if (nonzero) { + int jac; + uint16_t sqr[16], negone[16]; + mulmod256(sqr, in, in, mod); + uint16_to_signed30(&x, sqr); + /* Compute jacobi symbol of in^2, which must be 1 (or uncomputable). */ + jac = secp256k1_jacobi32_maybe_var(&x, &m); + CHECK(jac == 0 || jac == 1); + /* Then compute the jacobi symbol of -(in^2). x and -x have opposite + * jacobi symbols if and only if (mod % 4) == 3. */ + negone[0] = mod[0] - 1; + for (i = 1; i < 16; ++i) negone[i] = mod[i]; + mulmod256(sqr, sqr, negone, mod); + uint16_to_signed30(&x, sqr); + jac = secp256k1_jacobi32_maybe_var(&x, &m); + CHECK(jac == 0 || jac == 1 - (mod[0] & 2)); + } + + uint16_to_signed30(&x, in); + mutate_sign_signed30(&m.modulus); for (vartime = 0; vartime < 2; ++vartime) { /* compute inverse */ (vartime ? secp256k1_modinv32_var : secp256k1_modinv32)(&x, &m); @@ -1095,12 +1115,32 @@ static void test_modinv64_uint16(uint16_t* out, const uint16_t* in, const uint16 uint16_to_signed62(&x, in); nonzero = (x.v[0] | x.v[1] | x.v[2] | x.v[3] | x.v[4]) != 0; uint16_to_signed62(&m.modulus, mod); - mutate_sign_signed62(&m.modulus); /* compute 1/modulus mod 2^62 */ m.modulus_inv62 = modinv2p64(m.modulus.v[0]) & M62; CHECK(((m.modulus_inv62 * m.modulus.v[0]) & M62) == 1); + /* Test secp256k1_jacobi64_maybe_var. */ + if (nonzero) { + int jac; + uint16_t sqr[16], negone[16]; + mulmod256(sqr, in, in, mod); + uint16_to_signed62(&x, sqr); + /* Compute jacobi symbol of in^2, which must be 1 (or uncomputable). */ + jac = secp256k1_jacobi64_maybe_var(&x, &m); + CHECK(jac == 0 || jac == 1); + /* Then compute the jacobi symbol of -(in^2). x and -x have opposite + * jacobi symbols if and only if (mod % 4) == 3. */ + negone[0] = mod[0] - 1; + for (i = 1; i < 16; ++i) negone[i] = mod[i]; + mulmod256(sqr, sqr, negone, mod); + uint16_to_signed62(&x, sqr); + jac = secp256k1_jacobi64_maybe_var(&x, &m); + CHECK(jac == 0 || jac == 1 - (mod[0] & 2)); + } + + uint16_to_signed62(&x, in); + mutate_sign_signed62(&m.modulus); for (vartime = 0; vartime < 2; ++vartime) { /* compute inverse */ (vartime ? secp256k1_modinv64_var : secp256k1_modinv64)(&x, &m); From 6be01036c8a6da5043953d055ffb5920728fbff7 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Wed, 4 Jan 2023 16:05:34 -0500 Subject: [PATCH 41/47] Add secp256k1_fe_is_square_var function The implementation calls the secp256k1_modinvNN_jacobi_var code, falling back to computing a square root in the (extremely rare) case it failed converge. --- src/bench_internal.c | 14 ++++++++++++++ src/field.h | 3 +++ src/field_10x26_impl.h | 27 +++++++++++++++++++++++++++ src/field_5x52_impl.h | 27 +++++++++++++++++++++++++++ src/tests.c | 2 ++ 5 files changed, 73 insertions(+) diff --git a/src/bench_internal.c b/src/bench_internal.c index e1ef14fd..c248ab8e 100644 --- a/src/bench_internal.c +++ b/src/bench_internal.c @@ -219,6 +219,19 @@ static void bench_field_sqrt(void* arg, int iters) { CHECK(j <= iters); } +static void bench_field_is_square_var(void* arg, int iters) { + int i, j = 0; + bench_inv *data = (bench_inv*)arg; + secp256k1_fe t = data->fe[0]; + + for (i = 0; i < iters; i++) { + j += secp256k1_fe_is_square_var(&t); + secp256k1_fe_add(&t, &data->fe[1]); + secp256k1_fe_normalize_var(&t); + } + CHECK(j <= iters); +} + static void bench_group_double_var(void* arg, int iters) { int i; bench_inv *data = (bench_inv*)arg; @@ -371,6 +384,7 @@ int main(int argc, char **argv) { if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "mul")) run_benchmark("field_mul", bench_field_mul, bench_setup, NULL, &data, 10, iters*10); if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "inverse")) run_benchmark("field_inverse", bench_field_inverse, bench_setup, NULL, &data, 10, iters); if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "inverse")) run_benchmark("field_inverse_var", bench_field_inverse_var, bench_setup, NULL, &data, 10, iters); + if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "issquare")) run_benchmark("field_is_square_var", bench_field_is_square_var, bench_setup, NULL, &data, 10, iters); if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "sqrt")) run_benchmark("field_sqrt", bench_field_sqrt, bench_setup, NULL, &data, 10, iters); if (d || have_flag(argc, argv, "group") || have_flag(argc, argv, "double")) run_benchmark("group_double_var", bench_group_double_var, bench_setup, NULL, &data, 10, iters*10); diff --git a/src/field.h b/src/field.h index 4b57548b..ccb4327e 100644 --- a/src/field.h +++ b/src/field.h @@ -135,4 +135,7 @@ static void secp256k1_fe_half(secp256k1_fe *r); * magnitude set to 'm' and is normalized if (and only if) 'm' is zero. */ 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); + #endif /* SECP256K1_FIELD_H */ diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h index 5e6c63cf..72c56df0 100644 --- a/src/field_10x26_impl.h +++ b/src/field_10x26_impl.h @@ -1365,4 +1365,31 @@ static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *x) { VERIFY_CHECK(secp256k1_fe_normalizes_to_zero(r) == secp256k1_fe_normalizes_to_zero(&tmp)); } +static int secp256k1_fe_is_square_var(const secp256k1_fe *x) { + secp256k1_fe tmp; + secp256k1_modinv32_signed30 s; + int jac, ret; + + tmp = *x; + secp256k1_fe_normalize_var(&tmp); + /* secp256k1_jacobi32_maybe_var cannot deal with input 0. */ + if (secp256k1_fe_is_zero(&tmp)) return 1; + secp256k1_fe_to_signed30(&s, &tmp); + jac = secp256k1_jacobi32_maybe_var(&s, &secp256k1_const_modinfo_fe); + if (jac == 0) { + /* secp256k1_jacobi32_maybe_var failed to compute the Jacobi symbol. Fall back + * to computing a square root. This should be extremely rare with random + * input (except in VERIFY mode, where a lower iteration count is used). */ + 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; +} + #endif /* SECP256K1_FIELD_REPR_IMPL_H */ diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h index 985c486a..538991c7 100644 --- a/src/field_5x52_impl.h +++ b/src/field_5x52_impl.h @@ -664,4 +664,31 @@ static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *x) { #endif } +static int secp256k1_fe_is_square_var(const secp256k1_fe *x) { + secp256k1_fe tmp; + secp256k1_modinv64_signed62 s; + int jac, ret; + + tmp = *x; + secp256k1_fe_normalize_var(&tmp); + /* secp256k1_jacobi64_maybe_var cannot deal with input 0. */ + if (secp256k1_fe_is_zero(&tmp)) return 1; + secp256k1_fe_to_signed62(&s, &tmp); + jac = secp256k1_jacobi64_maybe_var(&s, &secp256k1_const_modinfo_fe); + if (jac == 0) { + /* secp256k1_jacobi64_maybe_var failed to compute the Jacobi symbol. Fall back + * to computing a square root. This should be extremely rare with random + * input (except in VERIFY mode, where a lower iteration count is used). */ + 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; +} + #endif /* SECP256K1_FIELD_REPR_IMPL_H */ diff --git a/src/tests.c b/src/tests.c index 9ee6c7b6..e80397cb 100644 --- a/src/tests.c +++ b/src/tests.c @@ -3299,8 +3299,10 @@ static void run_sqrt(void) { for (j = 0; j < COUNT; j++) { random_fe(&x); secp256k1_fe_sqr(&s, &x); + CHECK(secp256k1_fe_is_square_var(&s)); test_sqrt(&s, &x); secp256k1_fe_negate(&t, &s, 1); + CHECK(!secp256k1_fe_is_square_var(&t)); test_sqrt(&t, NULL); secp256k1_fe_mul(&t, &s, &ns); test_sqrt(&t, NULL); From ce3cfc78a6020d21be299e1e4f22cf8ef089194d Mon Sep 17 00:00:00 2001 From: Elliott Jin Date: Wed, 10 Nov 2021 10:37:44 -0800 Subject: [PATCH 42/47] doc: Describe Jacobi calculation in safegcd_implementation.md --- doc/safegcd_implementation.md | 52 +++++++++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/doc/safegcd_implementation.md b/doc/safegcd_implementation.md index 5216231e..5dbbb7bb 100644 --- a/doc/safegcd_implementation.md +++ b/doc/safegcd_implementation.md @@ -1,7 +1,7 @@ # The safegcd implementation in libsecp256k1 explained -This document explains the modular inverse implementation in the `src/modinv*.h` files. It is based -on the paper +This document explains the modular inverse and Jacobi symbol implementations in the `src/modinv*.h` files. +It is based on the paper ["Fast constant-time gcd computation and modular inversion"](https://gcd.cr.yp.to/papers.html#safegcd) by Daniel J. Bernstein and Bo-Yin Yang. The references below are for the Date: 2019.04.13 version. @@ -769,3 +769,51 @@ def modinv_var(M, Mi, x): d, e = update_de(d, e, t, M, Mi) return normalize(f, d, Mi) ``` + +## 8. From GCDs to Jacobi symbol + +We can also use a similar approach to calculate Jacobi symbol *(x | M)* by keeping track of an +extra variable *j*, for which at every step *(x | M) = j (g | f)*. As we update *f* and *g*, we +make corresponding updates to *j* using +[properties of the Jacobi symbol](https://en.wikipedia.org/wiki/Jacobi_symbol#Properties): +* *((g/2) | f)* is either *(g | f)* or *-(g | f)*, depending on the value of *f mod 8* (negating if it's *3* or *5*). +* *(f | g)* is either *(g | f)* or *-(g | f)*, depending on *f mod 4* and *g mod 4* (negating if both are *3*). + +These updates depend only on the values of *f* and *g* modulo *4* or *8*, and can thus be applied +very quickly, as long as we keep track of a few additional bits of *f* and *g*. Overall, this +calculation is slightly simpler than the one for the modular inverse because we no longer need to +keep track of *d* and *e*. + +However, one difficulty of this approach is that the Jacobi symbol *(a | n)* is only defined for +positive odd integers *n*, whereas in the original safegcd algorithm, *f, g* can take negative +values. We resolve this by using the following modified steps: + +```python + # Before + if delta > 0 and g & 1: + delta, f, g = 1 - delta, g, (g - f) // 2 + + # After + if delta > 0 and g & 1: + delta, f, g = 1 - delta, g, (g + f) // 2 +``` + +The algorithm is still correct, since the changed divstep, called a "posdivstep" (see section 8.4 +and E.5 in the paper) preserves *gcd(f, g)*. However, there's no proof that the modified algorithm +will converge. The justification for posdivsteps is completely empirical: in practice, it appears +that the vast majority of nonzero inputs converge to *f=g=gcd(f0, g0)* in a +number of steps proportional to their logarithm. + +Note that: +- We require inputs to satisfy *gcd(x, M) = 1*, as otherwise *f=1* is not reached. +- We require inputs *x &neq; 0*, because applying posdivstep with *g=0* has no effect. +- We need to update the termination condition from *g=0* to *f=1*. + +We account for the possibility of nonconvergence by only performing a bounded number of +posdivsteps, and then falling back to square-root based Jacobi calculation if a solution has not +yet been found. + +The optimizations in sections 3-7 above are described in the context of the original divsteps, but +in the C implementation we also adapt most of them (not including "avoiding modulus operations", +since it's not necessary to track *d, e*, and "constant-time operation", since we never calculate +Jacobi symbols for secret data) to the posdivsteps version. From 5660c137552c657da5265691dea0fb10faae6a76 Mon Sep 17 00:00:00 2001 From: Harshil Jani Date: Fri, 17 Feb 2023 14:08:06 +0530 Subject: [PATCH 43/47] prevent optimization in algorithms Signed-off-by: Harshil Jani Add secure_erase function to clear secrets Signed-off-by: Harshil Jani Update the function with good practices Signed-off-by: Harshil Jani Renaming random.h to examples_util.h Signed-off-by: Harshil Jani --- Makefile.am | 2 +- examples/ecdh.c | 13 ++++++------ examples/ecdsa.c | 8 +++---- examples/{random.h => examples_util.h} | 29 ++++++++++++++++++++++++++ examples/schnorr.c | 7 +++---- 5 files changed, 42 insertions(+), 17 deletions(-) rename examples/{random.h => examples_util.h} (69%) diff --git a/Makefile.am b/Makefile.am index 48ee2fcf..e3fdf4da 100644 --- a/Makefile.am +++ b/Makefile.am @@ -69,7 +69,7 @@ noinst_HEADERS += contrib/lax_der_parsing.h noinst_HEADERS += contrib/lax_der_parsing.c noinst_HEADERS += contrib/lax_der_privatekey_parsing.h noinst_HEADERS += contrib/lax_der_privatekey_parsing.c -noinst_HEADERS += examples/random.h +noinst_HEADERS += examples/examples_util.h PRECOMPUTED_LIB = libsecp256k1_precomputed.la noinst_LTLIBRARIES = $(PRECOMPUTED_LIB) diff --git a/examples/ecdh.c b/examples/ecdh.c index 027d52fd..4b7b7d61 100644 --- a/examples/ecdh.c +++ b/examples/ecdh.c @@ -14,8 +14,7 @@ #include #include -#include "random.h" - +#include "examples_util.h" int main(void) { unsigned char seckey1[32]; @@ -112,12 +111,12 @@ int main(void) { * example through "out of bounds" array access (see Heartbleed), Or the OS * swapping them to disk. Hence, we overwrite the secret key buffer with zeros. * - * TODO: Prevent these writes from being optimized out, as any good compiler + * Here we are preventing these writes from being optimized out, as any good compiler * will remove any writes that aren't used. */ - memset(seckey1, 0, sizeof(seckey1)); - memset(seckey2, 0, sizeof(seckey2)); - memset(shared_secret1, 0, sizeof(shared_secret1)); - memset(shared_secret2, 0, sizeof(shared_secret2)); + secure_erase(seckey1, sizeof(seckey1)); + secure_erase(seckey2, sizeof(seckey2)); + secure_erase(shared_secret1, sizeof(shared_secret1)); + secure_erase(shared_secret2, sizeof(shared_secret2)); return 0; } diff --git a/examples/ecdsa.c b/examples/ecdsa.c index 7e4f1b13..c4dd5687 100644 --- a/examples/ecdsa.c +++ b/examples/ecdsa.c @@ -13,9 +13,7 @@ #include -#include "random.h" - - +#include "examples_util.h" int main(void) { /* Instead of signing the message directly, we must sign a 32-byte hash. @@ -125,9 +123,9 @@ int main(void) { * example through "out of bounds" array access (see Heartbleed), Or the OS * swapping them to disk. Hence, we overwrite the secret key buffer with zeros. * - * TODO: Prevent these writes from being optimized out, as any good compiler + * Here we are preventing these writes from being optimized out, as any good compiler * will remove any writes that aren't used. */ - memset(seckey, 0, sizeof(seckey)); + secure_erase(seckey, sizeof(seckey)); return 0; } diff --git a/examples/random.h b/examples/examples_util.h similarity index 69% rename from examples/random.h rename to examples/examples_util.h index 439226f0..a52b1fa1 100644 --- a/examples/random.h +++ b/examples/examples_util.h @@ -71,3 +71,32 @@ static void print_hex(unsigned char* data, size_t size) { } printf("\n"); } + +#if defined(_MSC_VER) +// For SecureZeroMemory +#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) { +#if defined(_MSC_VER) + /* SecureZeroMemory is guaranteed not to be optimized out by MSVC. */ + SecureZeroMemory(ptr, len); +#elif defined(__GNUC__) + /* We use a memory barrier that scares the compiler away from optimizing out the memset. + * + * Quoting Adam Langley in commit ad1907fe73334d6c696c8539646c21b11178f20f + * in BoringSSL (ISC License): + * As best as we can tell, this is sufficient to break any optimisations that + * might try to eliminate "superfluous" memsets. + * This method used in memzero_explicit() the Linux kernel, too. Its advantage is that it is + * pretty efficient, because the compiler can still implement the memset() efficently, + * just not remove it entirely. See "Dead Store Elimination (Still) Considered Harmful" by + * Yang et al. (USENIX Security 2017) for more background. + */ + memset(ptr, 0, len); + __asm__ __volatile__("" : : "r"(ptr) : "memory"); +#else + void *(*volatile const volatile_memset)(void *, int, size_t) = memset; + volatile_memset(ptr, 0, len); +#endif +} diff --git a/examples/schnorr.c b/examples/schnorr.c index 207c45c4..0ff33f0f 100644 --- a/examples/schnorr.c +++ b/examples/schnorr.c @@ -15,7 +15,7 @@ #include #include -#include "random.h" +#include "examples_util.h" int main(void) { unsigned char msg[12] = "Hello World!"; @@ -140,9 +140,8 @@ int main(void) { * example through "out of bounds" array access (see Heartbleed), Or the OS * swapping them to disk. Hence, we overwrite the secret key buffer with zeros. * - * TODO: Prevent these writes from being optimized out, as any good compiler + * Here we are preventing these writes from being optimized out, as any good compiler * will remove any writes that aren't used. */ - memset(seckey, 0, sizeof(seckey)); - + secure_erase(seckey, sizeof(seckey)); return 0; } From b081f7e4cbfd27edc36e823dcd93537a46f7d2a6 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Wed, 1 Mar 2023 16:19:35 -0500 Subject: [PATCH 44/47] Add secp256k1_fe_add_int function --- src/field.h | 3 +++ src/field_10x26_impl.h | 14 ++++++++++++++ src/field_5x52_impl.h | 14 ++++++++++++++ src/group_impl.h | 4 ++-- src/tests.c | 11 ++++++++++- 5 files changed, 43 insertions(+), 3 deletions(-) diff --git a/src/field.h b/src/field.h index ccb4327e..64ceead4 100644 --- a/src/field.h +++ b/src/field.h @@ -85,6 +85,9 @@ static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a); * as an argument. The magnitude of the output is one higher. */ 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. */ static void secp256k1_fe_mul_int(secp256k1_fe *r, int a); diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h index 72c56df0..46b72ce7 100644 --- a/src/field_10x26_impl.h +++ b/src/field_10x26_impl.h @@ -482,6 +482,20 @@ SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_f #endif } +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; + r->normalized = 0; + secp256k1_fe_verify(r); +#endif +} + #if defined(USE_EXTERNAL_ASM) /* External assembler implementation */ diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h index 538991c7..4c4466ec 100644 --- a/src/field_5x52_impl.h +++ b/src/field_5x52_impl.h @@ -425,6 +425,20 @@ SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe *r, int a) { #endif } +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; + r->normalized = 0; + secp256k1_fe_verify(r); +#endif +} + SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a) { #ifdef VERIFY secp256k1_fe_verify(a); diff --git a/src/group_impl.h b/src/group_impl.h index 111ee68b..82ce3f8d 100644 --- a/src/group_impl.h +++ b/src/group_impl.h @@ -227,7 +227,7 @@ static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int o secp256k1_fe_sqr(&x2, x); secp256k1_fe_mul(&x3, x, &x2); r->infinity = 0; - secp256k1_fe_add(&x3, &secp256k1_fe_const_b); + secp256k1_fe_add_int(&x3, SECP256K1_B); if (!secp256k1_fe_sqrt(&r->y, &x3)) { return 0; } @@ -282,7 +282,7 @@ static int secp256k1_ge_is_valid_var(const secp256k1_ge *a) { /* y^2 = x^3 + 7 */ secp256k1_fe_sqr(&y2, &a->y); secp256k1_fe_sqr(&x3, &a->x); secp256k1_fe_mul(&x3, &x3, &a->x); - secp256k1_fe_add(&x3, &secp256k1_fe_const_b); + secp256k1_fe_add_int(&x3, SECP256K1_B); secp256k1_fe_normalize_weak(&x3); return secp256k1_fe_equal_var(&y2, &x3); } diff --git a/src/tests.c b/src/tests.c index e80397cb..1c0d7973 100644 --- a/src/tests.c +++ b/src/tests.c @@ -3093,6 +3093,7 @@ static void run_field_misc(void) { secp256k1_fe y; secp256k1_fe z; secp256k1_fe q; + int v; secp256k1_fe fe5 = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 5); int i, j; for (i = 0; i < 1000 * COUNT; i++) { @@ -3103,6 +3104,14 @@ static void run_field_misc(void) { random_fe_test(&x); } random_fe_non_zero(&y); + v = secp256k1_testrand_bits(15); + /* Test that fe_add_int is equivalent to fe_set_int + fe_add. */ + secp256k1_fe_set_int(&q, v); /* q = v */ + z = x; /* z = x */ + secp256k1_fe_add(&z, &q); /* z = x+v */ + q = x; /* q = x */ + secp256k1_fe_add_int(&q, v); /* q = x+v */ + CHECK(check_fe_equal(&q, &z)); /* Test the fe equality and comparison operations. */ CHECK(secp256k1_fe_cmp_var(&x, &x) == 0); CHECK(secp256k1_fe_equal_var(&x, &x)); @@ -3371,7 +3380,7 @@ static void test_inverse_field(secp256k1_fe* out, const secp256k1_fe* x, int var (var ? secp256k1_fe_inv_var : secp256k1_fe_inv)(&r, &r); /* r = 1/(x-1) */ secp256k1_fe_add(&l, &fe_minus_one); /* l = 1/x-1 */ (var ? secp256k1_fe_inv_var : secp256k1_fe_inv)(&l, &l); /* l = 1/(1/x-1) */ - secp256k1_fe_add(&l, &secp256k1_fe_one); /* l = 1/(1/x-1)+1 */ + secp256k1_fe_add_int(&l, 1); /* l = 1/(1/x-1)+1 */ secp256k1_fe_add(&l, &r); /* l = 1/(1/x-1)+1 + 1/(x-1) */ CHECK(secp256k1_fe_normalizes_to_zero_var(&l)); /* l == 0 */ } From 2ef1c9b38700b7cca2ee1aace2f020ee834729c0 Mon Sep 17 00:00:00 2001 From: Russell O'Connor Date: Mon, 6 Mar 2023 18:13:47 -0500 Subject: [PATCH 45/47] Update overflow check One does not simply check for integer overlow. --- src/modinv32_impl.h | 8 ++++---- src/modinv64_impl.h | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/modinv32_impl.h b/src/modinv32_impl.h index 028a5701..72065b45 100644 --- a/src/modinv32_impl.h +++ b/src/modinv32_impl.h @@ -415,10 +415,10 @@ static void secp256k1_modinv32_update_de_30(secp256k1_modinv32_signed30 *d, secp VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(d, 9, &modinfo->modulus, 1) < 0); /* d < modulus */ VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(e, 9, &modinfo->modulus, -2) > 0); /* e > -2*modulus */ VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(e, 9, &modinfo->modulus, 1) < 0); /* e < modulus */ - VERIFY_CHECK((labs(u) + labs(v)) >= 0); /* |u|+|v| doesn't overflow */ - VERIFY_CHECK((labs(q) + labs(r)) >= 0); /* |q|+|r| doesn't overflow */ - VERIFY_CHECK((labs(u) + labs(v)) <= M30 + 1); /* |u|+|v| <= 2^30 */ - VERIFY_CHECK((labs(q) + labs(r)) <= M30 + 1); /* |q|+|r| <= 2^30 */ + VERIFY_CHECK(labs(v) <= M30 + 1); /* |v| <= 2^30 */ + VERIFY_CHECK(labs(u) <= (M30 + 1 - labs(v))); /* |u|+|v| <= 2^30 */ + VERIFY_CHECK(labs(r) <= M30 + 1); /* |r| <= 2^30 */ + VERIFY_CHECK(labs(q) <= (M30 + 1 - labs(r))); /* |q|+|r| <= 2^30 */ #endif /* [md,me] start as zero; plus [u,q] if d is negative; plus [v,r] if e is negative. */ sd = d->v[8] >> 31; diff --git a/src/modinv64_impl.h b/src/modinv64_impl.h index df9aedff..ae596cf0 100644 --- a/src/modinv64_impl.h +++ b/src/modinv64_impl.h @@ -419,10 +419,10 @@ static void secp256k1_modinv64_update_de_62(secp256k1_modinv64_signed62 *d, secp VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(d, 5, &modinfo->modulus, 1) < 0); /* d < modulus */ VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(e, 5, &modinfo->modulus, -2) > 0); /* e > -2*modulus */ VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(e, 5, &modinfo->modulus, 1) < 0); /* e < modulus */ - VERIFY_CHECK((secp256k1_modinv64_abs(u) + secp256k1_modinv64_abs(v)) >= 0); /* |u|+|v| doesn't overflow */ - VERIFY_CHECK((secp256k1_modinv64_abs(q) + secp256k1_modinv64_abs(r)) >= 0); /* |q|+|r| doesn't overflow */ - VERIFY_CHECK((secp256k1_modinv64_abs(u) + secp256k1_modinv64_abs(v)) <= (int64_t)1 << 62); /* |u|+|v| <= 2^62 */ - VERIFY_CHECK((secp256k1_modinv64_abs(q) + secp256k1_modinv64_abs(r)) <= (int64_t)1 << 62); /* |q|+|r| <= 2^62 */ + VERIFY_CHECK(secp256k1_modinv64_abs(v) <= (int64_t)1 << 62); /* |v| <= 2^62 */ + VERIFY_CHECK(secp256k1_modinv64_abs(u) <= (((int64_t)1 << 62) - secp256k1_modinv64_abs(v))); /* |u|+|v| <= 2^62 */ + VERIFY_CHECK(secp256k1_modinv64_abs(r) <= (int64_t)1 << 62); /* |r| <= 2^62 */ + VERIFY_CHECK(secp256k1_modinv64_abs(q) <= (((int64_t)1 << 62) - secp256k1_modinv64_abs(r))); /* |q|+|r| <= 2^62 */ #endif /* [md,me] start as zero; plus [u,q] if d is negative; plus [v,r] if e is negative. */ sd = d4 >> 63; From d232112fa7e17fbbed7927bf02e8b1a0c54aeb53 Mon Sep 17 00:00:00 2001 From: Tim Ruffing Date: Tue, 7 Mar 2023 12:01:23 +0100 Subject: [PATCH 46/47] Update Changelog Fixes #1220. --- CHANGELOG.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 62a89f83..4c73cab0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,10 +7,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +#### Added + - Usage examples: Added a recommended method for securely clearing sensitive data, e.g., secret keys, from memory. + - Tests: Added a new test binary `noverify_tests`. This binary runs the tests without some additional checks present in the ordinary `tests` binary and is thereby closer to production binaries. The `noverify_tests` binary is automatically run as part of the `make check` target. + +#### Fixed + - Fixed declarations of API variables for MSVC (`__declspec(dllimport)`). This fixes MSVC builds of programs which link against a libsecp256k1 DLL dynamically and use API variables (and not only API functions). Unfortunately, the MSVC linker now will emit warning `LNK4217` when trying to link against libsecp256k1 statically. Pass `/ignore:4217` to the linker to suppress this warning. + #### Changed - Forbade cloning or destroying `secp256k1_context_static`. Create a new context instead of cloning the static context. (If this change breaks your code, your code is probably wrong.) - Forbade randomizing (copies of) `secp256k1_context_static`. Randomizing a copy of `secp256k1_context_static` did not have any effect and did not provide defense-in-depth protection against side-channel attacks. Create a new context if you want to benefit from randomization. +#### Removed + - Removed the configuration header `src/libsecp256k1-config.h`. We recommend passing flags to `./configure` to set configuration options (see `./configure --help`). If you cannot or do not want to use `./configure`, pass configuration flags such as `-DSECP256K1_ENABLE_MODULE_SCHNORRSIG` manually to the compiler (see the file `configure.ac` for supported flags). + ## [0.2.0] - 2022-12-12 #### Added From 5d8f53e31293c582fb3fe02157bc67d2eeccea77 Mon Sep 17 00:00:00 2001 From: Russell O'Connor Date: Tue, 7 Mar 2023 09:10:36 -0500 Subject: [PATCH 47/47] Remove redudent checks. These abs checks are implied by the subsequent line, and with the subsequent line written as it is, no underflow is possible with signed integers. --- src/modinv32_impl.h | 2 -- src/modinv64_impl.h | 2 -- 2 files changed, 4 deletions(-) diff --git a/src/modinv32_impl.h b/src/modinv32_impl.h index 72065b45..64375056 100644 --- a/src/modinv32_impl.h +++ b/src/modinv32_impl.h @@ -415,9 +415,7 @@ static void secp256k1_modinv32_update_de_30(secp256k1_modinv32_signed30 *d, secp VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(d, 9, &modinfo->modulus, 1) < 0); /* d < modulus */ VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(e, 9, &modinfo->modulus, -2) > 0); /* e > -2*modulus */ VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(e, 9, &modinfo->modulus, 1) < 0); /* e < modulus */ - VERIFY_CHECK(labs(v) <= M30 + 1); /* |v| <= 2^30 */ VERIFY_CHECK(labs(u) <= (M30 + 1 - labs(v))); /* |u|+|v| <= 2^30 */ - VERIFY_CHECK(labs(r) <= M30 + 1); /* |r| <= 2^30 */ VERIFY_CHECK(labs(q) <= (M30 + 1 - labs(r))); /* |q|+|r| <= 2^30 */ #endif /* [md,me] start as zero; plus [u,q] if d is negative; plus [v,r] if e is negative. */ diff --git a/src/modinv64_impl.h b/src/modinv64_impl.h index ae596cf0..e33727d3 100644 --- a/src/modinv64_impl.h +++ b/src/modinv64_impl.h @@ -419,9 +419,7 @@ static void secp256k1_modinv64_update_de_62(secp256k1_modinv64_signed62 *d, secp VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(d, 5, &modinfo->modulus, 1) < 0); /* d < modulus */ VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(e, 5, &modinfo->modulus, -2) > 0); /* e > -2*modulus */ VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(e, 5, &modinfo->modulus, 1) < 0); /* e < modulus */ - VERIFY_CHECK(secp256k1_modinv64_abs(v) <= (int64_t)1 << 62); /* |v| <= 2^62 */ VERIFY_CHECK(secp256k1_modinv64_abs(u) <= (((int64_t)1 << 62) - secp256k1_modinv64_abs(v))); /* |u|+|v| <= 2^62 */ - VERIFY_CHECK(secp256k1_modinv64_abs(r) <= (int64_t)1 << 62); /* |r| <= 2^62 */ VERIFY_CHECK(secp256k1_modinv64_abs(q) <= (((int64_t)1 << 62) - secp256k1_modinv64_abs(r))); /* |q|+|r| <= 2^62 */ #endif /* [md,me] start as zero; plus [u,q] if d is negative; plus [v,r] if e is negative. */