diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b1142202d..a6ff9e369 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -548,7 +548,8 @@ jobs: env: ${{ matrix.env_vars }} run: ./ci/ci.sh - - name: Symbol check + - &SYMBOL_CHECK_MACOS + name: Symbol check env: VIRTUAL_ENV: '${{ github.workspace }}/venv' run: | @@ -595,17 +596,7 @@ jobs: ln -s $(brew --prefix gcc)/bin/gcc-?? /usr/local/bin/gcc - *CI_SCRIPT_ON_HOST - - - name: Symbol check - env: - VIRTUAL_ENV: '${{ github.workspace }}/venv' - run: | - python3 --version - python3 -m venv $VIRTUAL_ENV - export PATH="$VIRTUAL_ENV/bin:$PATH" - python3 -m pip install lief - python3 ./tools/symbol-check.py .libs/libsecp256k1.dylib - + - *SYMBOL_CHECK_MACOS - *PRINT_LOGS win64-native: diff --git a/CHANGELOG.md b/CHANGELOG.md index e3ab6e04e..48cbdaf76 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.7.1] - 2026-01-26 + +#### Changed + - Tests: Introduced a unit test framework with support for parallel test execution, selective test running, and named command-line arguments. Run `./tests -help` for usage information. + +#### Fixed + - Increased the number of cases where the library attempts to clear secrets from the stack. + - build: Fixed x86_64 assembly feature check that could fail when user-provided `CFLAGS` included `-Werror`. This would cause the build to fall back to the slower C implementation instead of using the optimized x86_64 assembly. + +#### ABI Compatibility +The ABI is backward compatible with version 0.7.0. + ## [0.7.0] - 2025-07-21 #### Added @@ -190,7 +202,8 @@ This version was in fact never released. The number was given by the build system since the introduction of autotools in Jan 2014 (ea0fe5a5bf0c04f9cc955b2966b614f5f378c6f6). Therefore, this version number does not uniquely identify a set of source files. -[unreleased]: https://github.com/bitcoin-core/secp256k1/compare/v0.7.0...HEAD +[Unreleased]: https://github.com/bitcoin-core/secp256k1/compare/v0.7.1...HEAD +[0.7.1]: https://github.com/bitcoin-core/secp256k1/compare/v0.7.0...v0.7.1 [0.7.0]: https://github.com/bitcoin-core/secp256k1/compare/v0.6.0...v0.7.0 [0.6.0]: https://github.com/bitcoin-core/secp256k1/compare/v0.5.1...v0.6.0 [0.5.1]: https://github.com/bitcoin-core/secp256k1/compare/v0.5.0...v0.5.1 diff --git a/CMakeLists.txt b/CMakeLists.txt index e9b4c8ee5..2235c9cb5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ project(libsecp256k1 # The package (a.k.a. release) version is based on semantic versioning 2.0.0 of # the API. All changes in experimental modules are treated as # backwards-compatible and therefore at most increase the minor version. - VERSION 0.7.1 + VERSION 0.7.2 DESCRIPTION "Optimized C library for ECDSA signatures and secret/public key operations on curve secp256k1." HOMEPAGE_URL "https://github.com/bitcoin-core/secp256k1" LANGUAGES C @@ -22,7 +22,7 @@ list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake) # All changes in experimental modules are treated as if they don't affect the # interface and therefore only increase the revision. set(${PROJECT_NAME}_LIB_VERSION_CURRENT 6) -set(${PROJECT_NAME}_LIB_VERSION_REVISION 1) +set(${PROJECT_NAME}_LIB_VERSION_REVISION 2) set(${PROJECT_NAME}_LIB_VERSION_AGE 0) #============================= diff --git a/include/secp256k1.h b/include/secp256k1.h index b0a13b144..2799d4a1f 100644 --- a/include/secp256k1.h +++ b/include/secp256k1.h @@ -349,7 +349,8 @@ SECP256K1_API void secp256k1_context_destroy( * writes the message to stderr and calls abort. This default callback can be * replaced at link time if the preprocessor macro * USE_EXTERNAL_DEFAULT_CALLBACKS is defined, which is the case if the build - * has been configured with --enable-external-default-callbacks. Then the + * has been configured with --enable-external-default-callbacks (GNU Autotools) or + * -DSECP256K1_USE_EXTERNAL_DEFAULT_CALLBACKS=ON (CMake). Then the * following two symbols must be provided to link against: * - void secp256k1_default_illegal_callback_fn(const char *message, void *data); * - void secp256k1_default_error_callback_fn(const char *message, void *data); diff --git a/sage/gen_split_lambda_constants.sage b/sage/gen_split_lambda_constants.sage index 7d4359e0f..7a5761acd 100644 --- a/sage/gen_split_lambda_constants.sage +++ b/sage/gen_split_lambda_constants.sage @@ -81,6 +81,15 @@ assert (A1 + A2)/2 < sqrt(N) assert B1 < sqrt(N) assert B2 < sqrt(N) +# Verify connection to Eisenstein integers Z[w] where w = (-1 + sqrt(-3))/2. +# The group order N factors as N = pi * conj(pi) in Z[w], where pi = A - B*w +# is an Eisenstein prime with norm A^2 + A*B + B^2. The GLV endomorphism +# eigenvalue LAMBDA equals B/A mod N, which is the image of w^2 under the +# isomorphism Z[w]/(pi) -> Z/NZ (since w -> A/B and (A/B)^2 = B/A in Z/NZ). +A_EIS, B_EIS = -B1, A1 +assert A_EIS**2 + A_EIS*B_EIS + B_EIS**2 == N +assert Z(B_EIS / A_EIS) == LAMBDA + G1 = round((2**384)*B2/N) G2 = round((2**384)*(-B1)/N) diff --git a/src/bench.c b/src/bench.c index 8ba7623a0..a5231b71e 100644 --- a/src/bench.c +++ b/src/bench.c @@ -177,8 +177,6 @@ int main(int argc, char** argv) { bench_data data; int d = argc == 1; - int default_iters = 20000; - int iters = get_iters(default_iters); /* Check for invalid user arguments */ char* valid_args[] = {"ecdsa", "verify", "ecdsa_verify", "sign", "ecdsa_sign", "ecdh", "recover", @@ -188,6 +186,13 @@ int main(int argc, char** argv) { size_t valid_args_size = sizeof(valid_args)/sizeof(valid_args[0]); int invalid_args = have_invalid_args(argc, argv, valid_args, valid_args_size); + int default_iters = 20000; + int iters = get_iters(default_iters); + if (iters == 0) { + help(default_iters); + return EXIT_FAILURE; + } + if (argc > 1) { if (have_flag(argc, argv, "-h") || have_flag(argc, argv, "--help") @@ -205,7 +210,7 @@ int main(int argc, char** argv) { #ifndef ENABLE_MODULE_ECDH if (have_flag(argc, argv, "ecdh")) { fprintf(stderr, "./bench: ECDH module not enabled.\n"); - fprintf(stderr, "Use ./configure --enable-module-ecdh.\n\n"); + fprintf(stderr, "See README.md for configuration instructions.\n\n"); return EXIT_FAILURE; } #endif @@ -213,7 +218,7 @@ int main(int argc, char** argv) { #ifndef ENABLE_MODULE_RECOVERY if (have_flag(argc, argv, "recover") || have_flag(argc, argv, "ecdsa_recover")) { fprintf(stderr, "./bench: Public key recovery module not enabled.\n"); - fprintf(stderr, "Use ./configure --enable-module-recovery.\n\n"); + fprintf(stderr, "See README.md for configuration instructions.\n\n"); return EXIT_FAILURE; } #endif @@ -221,7 +226,7 @@ int main(int argc, char** argv) { #ifndef ENABLE_MODULE_SCHNORRSIG if (have_flag(argc, argv, "schnorrsig") || have_flag(argc, argv, "schnorrsig_sign") || have_flag(argc, argv, "schnorrsig_verify")) { fprintf(stderr, "./bench: Schnorr signatures module not enabled.\n"); - fprintf(stderr, "Use ./configure --enable-module-schnorrsig.\n\n"); + fprintf(stderr, "See README.md for configuration instructions.\n\n"); return EXIT_FAILURE; } #endif @@ -231,7 +236,7 @@ int main(int argc, char** argv) { have_flag(argc, argv, "encode") || have_flag(argc, argv, "decode") || have_flag(argc, argv, "ellswift_keygen") || have_flag(argc, argv, "ellswift_ecdh")) { fprintf(stderr, "./bench: ElligatorSwift module not enabled.\n"); - fprintf(stderr, "Use ./configure --enable-module-ellswift.\n\n"); + fprintf(stderr, "See README.md for configuration instructions.\n\n"); return EXIT_FAILURE; } #endif diff --git a/src/bench.h b/src/bench.h index 4e8e961b6..72a3f211b 100644 --- a/src/bench.h +++ b/src/bench.h @@ -150,7 +150,13 @@ static int have_invalid_args(int argc, char** argv, char** valid_args, size_t n) static int get_iters(int default_iters) { char* env = getenv("SECP256K1_BENCH_ITERS"); if (env) { - return strtol(env, NULL, 0); + char* endptr; + long int iters = strtol(env, &endptr, 0); + if (*endptr != '\0' || iters <= 0) { + printf("Error: Value of SECP256K1_BENCH_ITERS is not a positive integer: %s\n\n", env); + return 0; + } + return iters; } else { return default_iters; } diff --git a/src/bench_bppp.c b/src/bench_bppp.c index b74aec6c4..63ad8ceaa 100644 --- a/src/bench_bppp.c +++ b/src/bench_bppp.c @@ -29,6 +29,9 @@ static void bench_bppp(void* arg, int iters) { int main(void) { bench_bppp_data data; int iters = get_iters(32); + if (iters == 0) { + return EXIT_FAILURE; + } data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); diff --git a/src/bench_ecmult.c b/src/bench_ecmult.c index b2bab65d2..bcf8b4315 100644 --- a/src/bench_ecmult.c +++ b/src/bench_ecmult.c @@ -19,9 +19,12 @@ #define POINTS 32768 -static void help(char **argv) { +static void help(char **argv, int default_iters) { printf("Benchmark EC multiplication algorithms\n"); printf("\n"); + printf("The default number of iterations for each benchmark is %d. This can be\n", default_iters); + printf("customized using the SECP256K1_BENCH_ITERS environment variable.\n"); + printf("\n"); printf("Usage: %s \n", argv[0]); printf("The output shows the number of multiplied and summed points right after the\n"); printf("function name. The letter 'g' indicates that one of the points is the generator.\n"); @@ -308,7 +311,12 @@ int main(int argc, char **argv) { int i, p; size_t scratch_size; - int iters = get_iters(10000); + int default_iters = 10000; + int iters = get_iters(default_iters); + if (iters == 0) { + help(argv, default_iters); + return EXIT_FAILURE; + } data.ecmult_multi = secp256k1_ecmult_multi_var; @@ -316,7 +324,7 @@ int main(int argc, char **argv) { if(have_flag(argc, argv, "-h") || have_flag(argc, argv, "--help") || have_flag(argc, argv, "help")) { - help(argv); + help(argv, default_iters); return EXIT_SUCCESS; } else if(have_flag(argc, argv, "pippenger_wnaf")) { printf("Using pippenger_wnaf:\n"); @@ -328,13 +336,13 @@ int main(int argc, char **argv) { printf("Using simple algorithm:\n"); } else { fprintf(stderr, "%s: unrecognized argument '%s'.\n\n", argv[0], argv[1]); - help(argv); + help(argv, default_iters); return EXIT_FAILURE; } } data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); - scratch_size = secp256k1_strauss_scratch_size(POINTS) + STRAUSS_SCRATCH_OBJECTS*16; + scratch_size = secp256k1_strauss_scratch_size(POINTS) + STRAUSS_SCRATCH_OBJECTS*ALIGNMENT; if (!have_flag(argc, argv, "simple")) { data.scratch = secp256k1_scratch_space_create(data.ctx, scratch_size); } else { @@ -381,6 +389,8 @@ int main(int argc, char **argv) { run_ecmult_multi_bench(&data, i << p, 1, iters); } } + } else { + printf("Skipping some benchmarks due to SECP256K1_BENCH_ITERS <= 2\n"); } if (data.scratch != NULL) { diff --git a/src/bench_generator.c b/src/bench_generator.c index ecccecb78..93af61290 100644 --- a/src/bench_generator.c +++ b/src/bench_generator.c @@ -50,6 +50,9 @@ static void bench_generator_generate_blinded(void* arg, int iters) { int main(void) { bench_generator_t data; int iters = get_iters(20000); + if (iters == 0) { + return EXIT_FAILURE; + } data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); diff --git a/src/bench_internal.c b/src/bench_internal.c index e4fbcb9d7..3739a1d22 100644 --- a/src/bench_internal.c +++ b/src/bench_internal.c @@ -412,9 +412,13 @@ static void bench_context(void* arg, int iters) { int main(int argc, char **argv) { bench_inv data; + int d = argc == 1; /* default */ int default_iters = 20000; int iters = get_iters(default_iters); - int d = argc == 1; /* default */ + if (iters == 0) { + help(default_iters); + return EXIT_FAILURE; + } if (argc > 1) { if (have_flag(argc, argv, "-h") diff --git a/src/bench_rangeproof.c b/src/bench_rangeproof.c index 76893456c..add1e1e15 100644 --- a/src/bench_rangeproof.c +++ b/src/bench_rangeproof.c @@ -58,6 +58,9 @@ int main(void) { data.min_bits = 32; iters = data.min_bits*get_iters(32); + if (iters == 0) { + return EXIT_FAILURE; + } run_benchmark("rangeproof_verify_bit", bench_rangeproof, bench_rangeproof_setup, NULL, &data, 10, iters); diff --git a/src/bench_whitelist.c b/src/bench_whitelist.c index 6cbe6fd60..f02f1e86a 100644 --- a/src/bench_whitelist.c +++ b/src/bench_whitelist.c @@ -69,6 +69,9 @@ int main(void) { size_t n_keys = 30; secp256k1_scalar ssub; int iters = get_iters(5); + if (iters == 0) { + return EXIT_FAILURE; + } data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); diff --git a/src/eckey.h b/src/eckey.h index d54d44c99..c2bbc4703 100644 --- a/src/eckey.h +++ b/src/eckey.h @@ -15,7 +15,10 @@ #include "ecmult_gen.h" static int secp256k1_eckey_pubkey_parse(secp256k1_ge *elem, const unsigned char *pub, size_t size); -static int secp256k1_eckey_pubkey_serialize(secp256k1_ge *elem, unsigned char *pub, size_t *size, int compressed); +/** Serialize a group element (that is not allowed to be infinity) to a compressed public key (33 bytes). */ +static void secp256k1_eckey_pubkey_serialize33(secp256k1_ge *elem, unsigned char *pub33); +/** Serialize a group element (that is not allowed to be infinity) to an uncompressed public key (65 bytes). */ +static void secp256k1_eckey_pubkey_serialize65(secp256k1_ge *elem, unsigned char *pub65); static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar *key, const secp256k1_scalar *tweak); static int secp256k1_eckey_pubkey_tweak_add(secp256k1_ge *key, const secp256k1_scalar *tweak); diff --git a/src/eckey_impl.h b/src/eckey_impl.h index a88a5964d..48745e8fe 100644 --- a/src/eckey_impl.h +++ b/src/eckey_impl.h @@ -35,24 +35,23 @@ static int secp256k1_eckey_pubkey_parse(secp256k1_ge *elem, const unsigned char } } -static int secp256k1_eckey_pubkey_serialize(secp256k1_ge *elem, unsigned char *pub, size_t *size, int compressed) { - VERIFY_CHECK(compressed == 0 || compressed == 1); +static void secp256k1_eckey_pubkey_serialize33(secp256k1_ge *elem, unsigned char *pub33) { + VERIFY_CHECK(!secp256k1_ge_is_infinity(elem)); - if (secp256k1_ge_is_infinity(elem)) { - return 0; - } secp256k1_fe_normalize_var(&elem->x); secp256k1_fe_normalize_var(&elem->y); - secp256k1_fe_get_b32(&pub[1], &elem->x); - if (compressed) { - *size = 33; - pub[0] = secp256k1_fe_is_odd(&elem->y) ? SECP256K1_TAG_PUBKEY_ODD : SECP256K1_TAG_PUBKEY_EVEN; - } else { - *size = 65; - pub[0] = SECP256K1_TAG_PUBKEY_UNCOMPRESSED; - secp256k1_fe_get_b32(&pub[33], &elem->y); - } - return 1; + pub33[0] = secp256k1_fe_is_odd(&elem->y) ? SECP256K1_TAG_PUBKEY_ODD : SECP256K1_TAG_PUBKEY_EVEN; + secp256k1_fe_get_b32(&pub33[1], &elem->x); +} + +static void secp256k1_eckey_pubkey_serialize65(secp256k1_ge *elem, unsigned char *pub65) { + VERIFY_CHECK(!secp256k1_ge_is_infinity(elem)); + + secp256k1_fe_normalize_var(&elem->x); + secp256k1_fe_normalize_var(&elem->y); + pub65[0] = SECP256K1_TAG_PUBKEY_UNCOMPRESSED; + secp256k1_fe_get_b32(&pub65[1], &elem->x); + secp256k1_fe_get_b32(&pub65[33], &elem->y); } static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar *key, const secp256k1_scalar *tweak) { diff --git a/src/ecmult_const_impl.h b/src/ecmult_const_impl.h index 4f6620910..1d24aeaf3 100644 --- a/src/ecmult_const_impl.h +++ b/src/ecmult_const_impl.h @@ -87,17 +87,15 @@ static void secp256k1_ecmult_const_odd_multiples_table_globalz(secp256k1_ge *pre secp256k1_fe neg_y; \ VERIFY_CHECK((n) < (1U << ECMULT_CONST_GROUP_SIZE)); \ VERIFY_CHECK(index < (1U << (ECMULT_CONST_GROUP_SIZE - 1))); \ - /* Unconditionally set r->x = (pre)[m].x. r->y = (pre)[m].y. because it's either the correct one + /* Unconditionally set r->x = (pre)[m].x and r->y = (pre)[m].y because it's either the correct one * or will get replaced in the later iterations, this is needed to make sure `r` is initialized. */ \ - (r)->x = (pre)[m].x; \ - (r)->y = (pre)[m].y; \ + secp256k1_ge_set_xy((r), &(pre)[m].x, &(pre)[m].y); \ for (m = 1; m < ECMULT_CONST_TABLE_SIZE; m++) { \ /* This loop is used to avoid secret data in array indices. See * the comment in ecmult_gen_impl.h for rationale. */ \ secp256k1_fe_cmov(&(r)->x, &(pre)[m].x, m == index); \ secp256k1_fe_cmov(&(r)->y, &(pre)[m].y, m == index); \ } \ - (r)->infinity = 0; \ secp256k1_fe_negate(&neg_y, &(r)->y, 1); \ secp256k1_fe_cmov(&(r)->y, &neg_y, negative); \ } while(0) @@ -375,11 +373,14 @@ static int secp256k1_ecmult_const_xonly(secp256k1_fe* r, const secp256k1_fe *n, SECP256K1_FE_VERIFY_MAGNITUDE(&g, 2); - /* Compute base point P = (n*g, g^2), the effective affine version of (n*g, g^2, v), which has - * corresponding affine X coordinate n/d. */ - secp256k1_fe_mul(&p.x, &g, n); - secp256k1_fe_sqr(&p.y, &g); - p.infinity = 0; + /* Compute base point P = (n*g, g^2), the effective affine version of + * (n*g, g^2, v), which has corresponding affine X coordinate n/d. */ + { + secp256k1_fe x, y; + secp256k1_fe_mul(&x, &g, n); + secp256k1_fe_sqr(&y, &g); + secp256k1_ge_set_xy(&p, &x, &y); + } /* Perform x-only EC multiplication of P with q. */ VERIFY_CHECK(!secp256k1_scalar_is_zero(q)); diff --git a/src/ecmult_impl.h b/src/ecmult_impl.h index 0b53b3fcb..c421750da 100644 --- a/src/ecmult_impl.h +++ b/src/ecmult_impl.h @@ -75,7 +75,7 @@ static void secp256k1_ecmult_odd_multiples_table(int n, secp256k1_ge *pre_a, sec secp256k1_ge d_ge; int i; - VERIFY_CHECK(!a->infinity); + VERIFY_CHECK(!secp256k1_gej_is_infinity(a)); secp256k1_gej_double_var(&d, a, NULL); @@ -220,9 +220,24 @@ static int secp256k1_ecmult_wnaf(int *wnaf, int len, const secp256k1_scalar *a, return last_set_bit + 1; } +/* Same as secp256k1_ecmult_wnaf, but stores to int8_t array. Requires w <= 8. */ +static int secp256k1_ecmult_wnaf_small(int8_t *wnaf, int len, const secp256k1_scalar *a, int w) { + int wnaf_tmp[256]; + int ret, i; + + VERIFY_CHECK(2 <= w && w <= 8); + ret = secp256k1_ecmult_wnaf(wnaf_tmp, len, a, w); + + for (i = 0; i < len; i++) { + wnaf[i] = (int8_t)wnaf_tmp[i]; + } + + return ret; +} + struct secp256k1_strauss_point_state { - int wnaf_na_1[129]; - int wnaf_na_lam[129]; + int8_t wnaf_na_1[129]; + int8_t wnaf_na_lam[129]; int bits_na_1; int bits_na_lam; }; @@ -259,8 +274,8 @@ static void secp256k1_ecmult_strauss_wnaf(const struct secp256k1_strauss_state * secp256k1_scalar_split_lambda(&na_1, &na_lam, &na[np]); /* build wnaf representation for na_1 and na_lam. */ - state->ps[no].bits_na_1 = secp256k1_ecmult_wnaf(state->ps[no].wnaf_na_1, 129, &na_1, WINDOW_A); - state->ps[no].bits_na_lam = secp256k1_ecmult_wnaf(state->ps[no].wnaf_na_lam, 129, &na_lam, WINDOW_A); + state->ps[no].bits_na_1 = secp256k1_ecmult_wnaf_small(state->ps[no].wnaf_na_1, 129, &na_1, WINDOW_A); + state->ps[no].bits_na_lam = secp256k1_ecmult_wnaf_small(state->ps[no].wnaf_na_lam, 129, &na_lam, WINDOW_A); VERIFY_CHECK(state->ps[no].bits_na_1 <= 129); VERIFY_CHECK(state->ps[no].bits_na_lam <= 129); if (state->ps[no].bits_na_1 > bits) { @@ -341,7 +356,7 @@ static void secp256k1_ecmult_strauss_wnaf(const struct secp256k1_strauss_state * } } - if (!r->infinity) { + if (!secp256k1_gej_is_infinity(r)) { secp256k1_fe_mul(&r->z, &r->z, &Z); } } diff --git a/src/field.h b/src/field.h index 1f6ba7460..e3f0234f5 100644 --- a/src/field.h +++ b/src/field.h @@ -307,7 +307,8 @@ static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe */ static void secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a); -/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized.*/ +/** If flag is 1, set *r equal to *a; if flag is 0, leave it. Constant-time. + * Both *r and *a must be initialized. Flag must be 0 or 1. */ static void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag); /** Conditionally move a field element in constant time. diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h index ea14c2731..aa45434d9 100644 --- a/src/field_10x26_impl.h +++ b/src/field_10x26_impl.h @@ -1014,6 +1014,7 @@ SECP256K1_INLINE static void secp256k1_fe_impl_sqr(secp256k1_fe *r, const secp25 SECP256K1_INLINE static void secp256k1_fe_impl_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) { uint32_t mask0, mask1; volatile int vflag = flag; + VERIFY_CHECK(flag == 0 || flag == 1); SECP256K1_CHECKMEM_CHECK_VERIFY(r->n, sizeof(r->n)); mask0 = vflag + ~((uint32_t)0); mask1 = ~mask0; @@ -1097,6 +1098,7 @@ static SECP256K1_INLINE void secp256k1_fe_impl_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; volatile int vflag = flag; + VERIFY_CHECK(flag == 0 || flag == 1); SECP256K1_CHECKMEM_CHECK_VERIFY(r->n, sizeof(r->n)); mask0 = vflag + ~((uint32_t)0); mask1 = ~mask0; diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h index 46dca6b98..3a976135e 100644 --- a/src/field_5x52_impl.h +++ b/src/field_5x52_impl.h @@ -349,6 +349,7 @@ SECP256K1_INLINE static void secp256k1_fe_impl_sqr(secp256k1_fe *r, const secp25 SECP256K1_INLINE static void secp256k1_fe_impl_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) { uint64_t mask0, mask1; volatile int vflag = flag; + VERIFY_CHECK(flag == 0 || flag == 1); SECP256K1_CHECKMEM_CHECK_VERIFY(r->n, sizeof(r->n)); mask0 = vflag + ~((uint64_t)0); mask1 = ~mask0; @@ -416,6 +417,7 @@ static SECP256K1_INLINE void secp256k1_fe_impl_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; volatile int vflag = flag; + VERIFY_CHECK(flag == 0 || flag == 1); SECP256K1_CHECKMEM_CHECK_VERIFY(r->n, sizeof(r->n)); mask0 = vflag + ~((uint64_t)0); mask1 = ~mask0; diff --git a/src/group.h b/src/group.h index 70968c1c2..81e17c1e8 100644 --- a/src/group.h +++ b/src/group.h @@ -178,10 +178,12 @@ static void secp256k1_ge_to_storage(secp256k1_ge_storage *r, const secp256k1_ge /** Convert a group element back from the storage type. */ static void secp256k1_ge_from_storage(secp256k1_ge *r, const secp256k1_ge_storage *a); -/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized.*/ +/** If flag is 1, set *r equal to *a; if flag is 0, leave it. Constant-time. + * Both *r and *a must be initialized. Flag must be 0 or 1. */ static void secp256k1_gej_cmov(secp256k1_gej *r, const secp256k1_gej *a, int flag); -/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized.*/ +/** If flag is 1, set *r equal to *a; if flag is 0, leave it. Constant-time. + * Both *r and *a must be initialized. Flag must be 0 or 1. */ static void secp256k1_ge_storage_cmov(secp256k1_ge_storage *r, const secp256k1_ge_storage *a, int flag); /** Rescale a jacobian point by b which must be non-zero. Constant-time. */ diff --git a/src/group_impl.h b/src/group_impl.h index 5dc9d1248..8be9a9851 100644 --- a/src/group_impl.h +++ b/src/group_impl.h @@ -906,6 +906,7 @@ static void secp256k1_ge_from_storage(secp256k1_ge *r, const secp256k1_ge_storag static SECP256K1_INLINE void secp256k1_gej_cmov(secp256k1_gej *r, const secp256k1_gej *a, int flag) { SECP256K1_GEJ_VERIFY(r); SECP256K1_GEJ_VERIFY(a); + VERIFY_CHECK(flag == 0 || flag == 1); secp256k1_fe_cmov(&r->x, &a->x, flag); secp256k1_fe_cmov(&r->y, &a->y, flag); @@ -916,6 +917,7 @@ static SECP256K1_INLINE void secp256k1_gej_cmov(secp256k1_gej *r, const secp256k } static SECP256K1_INLINE void secp256k1_ge_storage_cmov(secp256k1_ge_storage *r, const secp256k1_ge_storage *a, int flag) { + VERIFY_CHECK(flag == 0 || flag == 1); secp256k1_fe_storage_cmov(&r->x, &a->x, flag); secp256k1_fe_storage_cmov(&r->y, &a->y, flag); } diff --git a/src/modules/bppp/bppp_util.h b/src/modules/bppp/bppp_util.h index 1debfb92c..ec979c69c 100644 --- a/src/modules/bppp/bppp_util.h +++ b/src/modules/bppp/bppp_util.h @@ -47,8 +47,11 @@ static int secp256k1_bppp_parse_one_of_points(secp256k1_ge *pt, const unsigned c /* Outputs a serialized point in compressed form. Returns 0 at point at infinity. */ static int secp256k1_bppp_serialize_pt(unsigned char *output, secp256k1_ge *lpt) { - size_t size; - return secp256k1_eckey_pubkey_serialize(lpt, output, &size, 1 /*compressed*/); + if (secp256k1_ge_is_infinity(lpt)) { + return 0; + } + secp256k1_eckey_pubkey_serialize33(lpt, output); + return 1; } /* little-endian encodes a uint64 */ diff --git a/src/modules/ecdsa_adaptor/dleq_impl.h b/src/modules/ecdsa_adaptor/dleq_impl.h index 11d2d6675..60e63a34a 100644 --- a/src/modules/ecdsa_adaptor/dleq_impl.h +++ b/src/modules/ecdsa_adaptor/dleq_impl.h @@ -20,16 +20,13 @@ static void secp256k1_nonce_function_dleq_sha256_tagged(secp256k1_sha256 *sha) { /* algo argument for nonce_function_ecdsa_adaptor to derive the nonce using a tagged hash function. */ static const unsigned char dleq_algo[] = {'D','L','E','Q'}; -static int secp256k1_dleq_hash_point(secp256k1_sha256 *sha, secp256k1_ge *p) { +static void secp256k1_dleq_hash_point(secp256k1_sha256 *sha, secp256k1_ge *p) { unsigned char buf[33]; size_t size = 33; - if (!secp256k1_eckey_pubkey_serialize(p, buf, &size, 1)) { - return 0; - } + secp256k1_eckey_pubkey_serialize33(p, buf); secp256k1_sha256_write(sha, buf, size); - return 1; } static int secp256k1_dleq_nonce(secp256k1_scalar *k, const unsigned char *sk32, const unsigned char *gen2_33, const unsigned char *p1_33, const unsigned char *p2_33, secp256k1_nonce_function_hardened_ecdsa_adaptor noncefp, void *ndata) { @@ -95,18 +92,11 @@ static int secp256k1_dleq_prove(const secp256k1_context* ctx, secp256k1_scalar * unsigned char gen2_33[33]; unsigned char p1_33[33]; unsigned char p2_33[33]; - size_t pubkey_size = 33; int ret; - if (!secp256k1_eckey_pubkey_serialize(gen2, gen2_33, &pubkey_size, 1)) { - return 0; - } - if (!secp256k1_eckey_pubkey_serialize(p1, p1_33, &pubkey_size, 1)) { - return 0; - } - if (!secp256k1_eckey_pubkey_serialize(p2, p2_33, &pubkey_size, 1)) { - return 0; - } + secp256k1_eckey_pubkey_serialize33(gen2, gen2_33); + secp256k1_eckey_pubkey_serialize33(p1, p1_33); + secp256k1_eckey_pubkey_serialize33(p2, p2_33); secp256k1_scalar_get_b32(sk32, sk); diff --git a/src/modules/ecdsa_adaptor/main_impl.h b/src/modules/ecdsa_adaptor/main_impl.h index e97bb5a0e..e43a4222a 100644 --- a/src/modules/ecdsa_adaptor/main_impl.h +++ b/src/modules/ecdsa_adaptor/main_impl.h @@ -11,20 +11,12 @@ #include "dleq_impl.h" /* (R, R', s', dleq_proof) */ -static int secp256k1_ecdsa_adaptor_sig_serialize(unsigned char *adaptor_sig162, secp256k1_ge *r, secp256k1_ge *rp, const secp256k1_scalar *sp, const secp256k1_scalar *dleq_proof_e, const secp256k1_scalar *dleq_proof_s) { - size_t size = 33; - - if (!secp256k1_eckey_pubkey_serialize(r, adaptor_sig162, &size, 1)) { - return 0; - } - if (!secp256k1_eckey_pubkey_serialize(rp, &adaptor_sig162[33], &size, 1)) { - return 0; - } +static void secp256k1_ecdsa_adaptor_sig_serialize(unsigned char *adaptor_sig162, secp256k1_ge *r, secp256k1_ge *rp, const secp256k1_scalar *sp, const secp256k1_scalar *dleq_proof_e, const secp256k1_scalar *dleq_proof_s) { + secp256k1_eckey_pubkey_serialize33(r, adaptor_sig162); + secp256k1_eckey_pubkey_serialize33(rp, &adaptor_sig162[33]); secp256k1_scalar_get_b32(&adaptor_sig162[66], sp); secp256k1_scalar_get_b32(&adaptor_sig162[98], dleq_proof_e); secp256k1_scalar_get_b32(&adaptor_sig162[130], dleq_proof_s); - - return 1; } static int secp256k1_ecdsa_adaptor_sig_deserialize(secp256k1_ge *r, secp256k1_scalar *sigr, secp256k1_ge *rp, secp256k1_scalar *sp, secp256k1_scalar *dleq_proof_e, secp256k1_scalar *dleq_proof_s, const unsigned char *adaptor_sig162) { @@ -162,7 +154,6 @@ int secp256k1_ecdsa_adaptor_encrypt(const secp256k1_context* ctx, unsigned char secp256k1_scalar n; unsigned char nonce32[32] = { 0 }; unsigned char buf33[33]; - size_t size = 33; int ret = 1; VERIFY_CHECK(ctx != NULL); @@ -183,7 +174,7 @@ int secp256k1_ecdsa_adaptor_encrypt(const secp256k1_context* ctx, unsigned char return 0; } - secp256k1_eckey_pubkey_serialize(&enckey_ge, buf33, &size, 1); + secp256k1_eckey_pubkey_serialize33(&enckey_ge, buf33); ret &= !!noncefp(nonce32, msg32, seckey32, buf33, ecdsa_adaptor_algo, sizeof(ecdsa_adaptor_algo), ndata); secp256k1_scalar_set_b32(&k, nonce32, NULL); ret &= !secp256k1_scalar_is_zero(&k); @@ -222,7 +213,7 @@ int secp256k1_ecdsa_adaptor_encrypt(const secp256k1_context* ctx, unsigned char ret &= !secp256k1_scalar_is_zero(&sp); /* return (R, R', s', dleq_proof) */ - ret &= secp256k1_ecdsa_adaptor_sig_serialize(adaptor_sig162, &nonce_pts[1], &nonce_pts[0], &sp, &dleq_proof_e, &dleq_proof_s); + secp256k1_ecdsa_adaptor_sig_serialize(adaptor_sig162, &nonce_pts[1], &nonce_pts[0], &sp, &dleq_proof_e, &dleq_proof_s); secp256k1_memczero(adaptor_sig162, 162, !ret); secp256k1_memclear_explicit(nonce32, sizeof(nonce32)); @@ -319,10 +310,10 @@ int secp256k1_ecdsa_adaptor_recover(const secp256k1_context* ctx, unsigned char secp256k1_scalar s, r; secp256k1_scalar deckey; secp256k1_ge enckey_expected_ge; + secp256k1_ge enckey_ge; secp256k1_gej enckey_expected_gej; unsigned char enckey33[33]; unsigned char enckey_expected33[33]; - size_t size = 33; int ret = 1; VERIFY_CHECK(ctx != NULL); @@ -349,23 +340,21 @@ int secp256k1_ecdsa_adaptor_recover(const secp256k1_context* ctx, unsigned char /* We declassify non-secret enckey_expected_ge to allow using it as a * branch point. */ secp256k1_declassify(ctx, &enckey_expected_ge, sizeof(enckey_expected_ge)); - if (!secp256k1_eckey_pubkey_serialize(&enckey_expected_ge, enckey_expected33, &size, 1)) { - /* Unreachable from tests (and other VERIFY builds) and therefore this - * branch should be ignored in test coverage analysis. - * - * Proof: - * eckey_pubkey_serialize fails <=> deckey = 0 - * deckey = 0 <=> s^-1 = 0 or sp = 0 - * case 1: s^-1 = 0 impossible by the definition of multiplicative - * inverse and because the scalar_inverse implementation - * VERIFY_CHECKs that the inputs are valid scalars. - * case 2: sp = 0 impossible because ecdsa_adaptor_sig_deserialize would have already failed - */ - return 0; - } - if (!secp256k1_ec_pubkey_serialize(ctx, enckey33, &size, enckey, SECP256K1_EC_COMPRESSED)) { + /* enckey_expected_ge cannot be infinity: + * + * Proof: + * enckey_expected_ge is infinity <=> deckey = 0 + * deckey = 0 <=> s^-1 = 0 or sp = 0 + * case 1: s^-1 = 0 impossible by the definition of multiplicative + * inverse and because the scalar_inverse implementation + * VERIFY_CHECKs that the inputs are valid scalars. + * case 2: sp = 0 impossible because ecdsa_adaptor_sig_deserialize would have already failed + */ + secp256k1_eckey_pubkey_serialize33(&enckey_expected_ge, enckey_expected33); + if (!secp256k1_pubkey_load(ctx, &enckey_ge, enckey)) { return 0; } + secp256k1_eckey_pubkey_serialize33(&enckey_ge, enckey33); if (secp256k1_memcmp_var(&enckey_expected33[1], &enckey33[1], 32) != 0) { return 0; } diff --git a/src/modules/ecdsa_adaptor/tests_impl.h b/src/modules/ecdsa_adaptor/tests_impl.h index 5e41a9c0c..3abc81277 100644 --- a/src/modules/ecdsa_adaptor/tests_impl.h +++ b/src/modules/ecdsa_adaptor/tests_impl.h @@ -39,7 +39,6 @@ static void dleq_tests_internal(void) { unsigned char p2_33[33]; unsigned char aux_rand[32]; int i; - size_t pubkey_size = 33; rand_point(&gen2); rand_scalar(&sk); @@ -62,19 +61,12 @@ static void dleq_tests_internal(void) { CHECK(secp256k1_dleq_verify(&s, &e, &p1, &p_tmp, &p2) == 0); CHECK(secp256k1_dleq_verify(&s, &e, &p1, &gen2, &p_tmp) == 0); } - { - secp256k1_ge p_inf; - secp256k1_ge_set_infinity(&p_inf); - CHECK(secp256k1_dleq_prove(CTX, &s, &e, &sk, &p_inf, &p1, &p2, NULL, NULL) == 0); - CHECK(secp256k1_dleq_prove(CTX, &s, &e, &sk, &gen2, &p_inf, &p2, NULL, NULL) == 0); - CHECK(secp256k1_dleq_prove(CTX, &s, &e, &sk, &gen2, &p1, &p_inf, NULL, NULL) == 0); - } /* Nonce tests */ secp256k1_scalar_get_b32(sk32, &sk); - CHECK(secp256k1_eckey_pubkey_serialize(&gen2, gen2_33, &pubkey_size, 1)); - CHECK(secp256k1_eckey_pubkey_serialize(&p1, p1_33, &pubkey_size, 1)); - CHECK(secp256k1_eckey_pubkey_serialize(&p2, p2_33, &pubkey_size, 1)); + secp256k1_eckey_pubkey_serialize33(&gen2, gen2_33); + secp256k1_eckey_pubkey_serialize33(&p1, p1_33); + secp256k1_eckey_pubkey_serialize33(&p2, p2_33); CHECK(secp256k1_dleq_nonce(&k, sk32, gen2_33, p1_33, p2_33, NULL, NULL) == 1); testrand_bytes_test(sk32, sizeof(sk32)); @@ -165,7 +157,7 @@ static void test_ecdsa_adaptor_spec_vectors_check_serialization(const unsigned c CHECK(expected == secp256k1_ecdsa_adaptor_sig_deserialize(&r, &sigr, &rp, &sp, &dleq_proof_e, &dleq_proof_s, adaptor_sig162)); if (expected == 1) { - CHECK(secp256k1_ecdsa_adaptor_sig_serialize(buf, &r, &rp, &sp, &dleq_proof_e, &dleq_proof_s) == 1); + secp256k1_ecdsa_adaptor_sig_serialize(buf, &r, &rp, &sp, &dleq_proof_e, &dleq_proof_s); CHECK(secp256k1_memcmp_var(buf, adaptor_sig162, 162) == 0); } } @@ -896,18 +888,12 @@ static void adaptor_tests_internal(void) { secp256k1_scalar sigr; secp256k1_scalar sp; secp256k1_scalar dleq_proof_s, dleq_proof_e; - secp256k1_ge p_inf; unsigned char adaptor_sig_tmp[162]; CHECK(secp256k1_ecdsa_adaptor_sig_deserialize(&r, &sigr, &rp, &sp, &dleq_proof_e, &dleq_proof_s, adaptor_sig) == 1); - CHECK(secp256k1_ecdsa_adaptor_sig_serialize(adaptor_sig_tmp, &r, &rp, &sp, &dleq_proof_e, &dleq_proof_s) == 1); + secp256k1_ecdsa_adaptor_sig_serialize(adaptor_sig_tmp, &r, &rp, &sp, &dleq_proof_e, &dleq_proof_s); CHECK(secp256k1_memcmp_var(adaptor_sig_tmp, adaptor_sig, sizeof(adaptor_sig_tmp)) == 0); - - /* Test adaptor_sig_serialize points at infinity */ - secp256k1_ge_set_infinity(&p_inf); - CHECK(secp256k1_ecdsa_adaptor_sig_serialize(adaptor_sig_tmp, &p_inf, &rp, &sp, &dleq_proof_e, &dleq_proof_s) == 0); - CHECK(secp256k1_ecdsa_adaptor_sig_serialize(adaptor_sig_tmp, &r, &p_inf, &sp, &dleq_proof_e, &dleq_proof_s) == 0); } { /* Test adaptor_sig_deserialize */ diff --git a/src/modules/ellswift/main_impl.h b/src/modules/ellswift/main_impl.h index 0d13f7342..096f4a3c7 100644 --- a/src/modules/ellswift/main_impl.h +++ b/src/modules/ellswift/main_impl.h @@ -406,19 +406,12 @@ int secp256k1_ellswift_encode(const secp256k1_context *ctx, unsigned char *ell64 if (secp256k1_pubkey_load(ctx, &p, pubkey)) { secp256k1_fe t; unsigned char p64[64] = {0}; - size_t ser_size; - int ser_ret; secp256k1_sha256 hash; /* Set up hasher state; the used RNG is H(pubkey || "\x00"*31 || rnd32 || cnt++), using * BIP340 tagged hash with tag "secp256k1_ellswift_encode". */ secp256k1_ellswift_sha256_init_encode(&hash); - ser_ret = secp256k1_eckey_pubkey_serialize(&p, p64, &ser_size, 1); -#ifdef VERIFY - VERIFY_CHECK(ser_ret && ser_size == 33); -#else - (void)ser_ret; -#endif + secp256k1_eckey_pubkey_serialize33(&p, p64); secp256k1_sha256_write(&hash, p64, sizeof(p64)); secp256k1_sha256_write(&hash, rnd32, 32); diff --git a/src/modules/ellswift/tests_impl.h b/src/modules/ellswift/tests_impl.h index 63c36e7ff..4cc7f4b55 100644 --- a/src/modules/ellswift/tests_impl.h +++ b/src/modules/ellswift/tests_impl.h @@ -177,9 +177,9 @@ static int ellswift_xdh_hash_x32(unsigned char *output, const unsigned char *x32 return 1; } -void run_ellswift_tests(void) { - int i = 0; - /* Test vectors. */ +/* Run the test vectors for ellswift encoding */ +void ellswift_encoding_test_vectors_tests(void) { + int i; for (i = 0; (unsigned)i < sizeof(ellswift_xswiftec_inv_tests) / sizeof(ellswift_xswiftec_inv_tests[0]); ++i) { const struct ellswift_xswiftec_inv_test *testcase = &ellswift_xswiftec_inv_tests[i]; int c; @@ -195,6 +195,11 @@ void run_ellswift_tests(void) { } } } +} + +/* Run the test vectors for ellswift decoding */ +void ellswift_decoding_test_vectors_tests(void) { + int i; for (i = 0; (unsigned)i < sizeof(ellswift_decode_tests) / sizeof(ellswift_decode_tests[0]); ++i) { const struct ellswift_decode_test *testcase = &ellswift_decode_tests[i]; secp256k1_pubkey pubkey; @@ -207,6 +212,11 @@ void run_ellswift_tests(void) { CHECK(fe_equal(&testcase->x, &ge.x)); CHECK(secp256k1_fe_is_odd(&ge.y) == testcase->odd_y); } +} + +/* Run the test vectors for ellswift expected xdh BIP324 shared secrets */ +void ellswift_xdh_test_vectors_tests(void) { + int i; for (i = 0; (unsigned)i < sizeof(ellswift_xdh_tests_bip324) / sizeof(ellswift_xdh_tests_bip324[0]); ++i) { const struct ellswift_xdh_test *test = &ellswift_xdh_tests_bip324[i]; unsigned char shared_secret[32]; @@ -223,7 +233,11 @@ void run_ellswift_tests(void) { CHECK(ret); CHECK(secp256k1_memcmp_var(shared_secret, test->shared_secret, 32) == 0); } - /* Verify that secp256k1_ellswift_encode + decode roundtrips. */ +} + +/* Verify that secp256k1_ellswift_encode + decode roundtrips */ +void ellswift_encode_decode_roundtrip_tests(void) { + int i; for (i = 0; i < 1000 * COUNT; i++) { unsigned char rnd32[32]; unsigned char ell64[64]; @@ -240,7 +254,11 @@ void run_ellswift_tests(void) { /* Compare with original. */ CHECK(secp256k1_ge_eq_var(&g, &g2)); } - /* Verify the behavior of secp256k1_ellswift_create */ +} + +/* Verify the behavior of secp256k1_ellswift_create */ +void ellswift_create_tests(void) { + int i; for (i = 0; i < 400 * COUNT; i++) { unsigned char auxrnd32[32], sec32[32]; secp256k1_scalar sec; @@ -262,7 +280,11 @@ void run_ellswift_tests(void) { secp256k1_ecmult(&res, NULL, &secp256k1_scalar_zero, &sec); CHECK(secp256k1_gej_eq_ge_var(&res, &dec)); } - /* Verify that secp256k1_ellswift_xdh computes the right shared X coordinate. */ +} + +/* Verify that secp256k1_ellswift_xdh computes the right shared X coordinate */ +void ellswift_compute_shared_secret_tests(void) { + int i; for (i = 0; i < 800 * COUNT; i++) { unsigned char ell64[64], sec32[32], share32[32]; secp256k1_scalar sec; @@ -293,6 +315,10 @@ void run_ellswift_tests(void) { /* Compare. */ CHECK(fe_equal(&res.x, &share_x)); } +} + +void ellswift_xdh_correctness_tests(void) { + int i; /* Verify the joint behavior of secp256k1_ellswift_xdh */ for (i = 0; i < 200 * COUNT; i++) { unsigned char auxrnd32a[32], auxrnd32b[32], auxrnd32a_bad[32], auxrnd32b_bad[32]; @@ -403,41 +429,47 @@ void run_ellswift_tests(void) { CHECK(secp256k1_memcmp_var(share32_bad, share32b, 32) != 0); } } +} - /* Test hash initializers. */ - { - secp256k1_sha256 sha_optimized; - /* "secp256k1_ellswift_encode" */ - static const unsigned char encode_tag[] = {'s', 'e', 'c', 'p', '2', '5', '6', 'k', '1', '_', 'e', 'l', 'l', 's', 'w', 'i', 'f', 't', '_', 'e', 'n', 'c', 'o', 'd', 'e'}; - /* "secp256k1_ellswift_create" */ - static const unsigned char create_tag[] = {'s', 'e', 'c', 'p', '2', '5', '6', 'k', '1', '_', 'e', 'l', 'l', 's', 'w', 'i', 'f', 't', '_', 'c', 'r', 'e', 'a', 't', 'e'}; - /* "bip324_ellswift_xonly_ecdh" */ - static const unsigned char bip324_tag[] = {'b', 'i', 'p', '3', '2', '4', '_', 'e', 'l', 'l', 's', 'w', 'i', 'f', 't', '_', 'x', 'o', 'n', 'l', 'y', '_', 'e', 'c', 'd', 'h'}; +/* Test hash initializers */ +void ellswift_hash_init_tests(void) { + secp256k1_sha256 sha_optimized; + /* "secp256k1_ellswift_encode" */ + static const unsigned char encode_tag[] = {'s', 'e', 'c', 'p', '2', '5', '6', 'k', '1', '_', 'e', 'l', 'l', 's', 'w', 'i', 'f', 't', '_', 'e', 'n', 'c', 'o', 'd', 'e'}; + /* "secp256k1_ellswift_create" */ + static const unsigned char create_tag[] = {'s', 'e', 'c', 'p', '2', '5', '6', 'k', '1', '_', 'e', 'l', 'l', 's', 'w', 'i', 'f', 't', '_', 'c', 'r', 'e', 'a', 't', 'e'}; + /* "bip324_ellswift_xonly_ecdh" */ + static const unsigned char bip324_tag[] = {'b', 'i', 'p', '3', '2', '4', '_', 'e', 'l', 'l', 's', 'w', 'i', 'f', 't', '_', 'x', 'o', 'n', 'l', 'y', '_', 'e', 'c', 'd', 'h'}; - /* Check that hash initialized by - * secp256k1_ellswift_sha256_init_encode has the expected - * state. */ - secp256k1_ellswift_sha256_init_encode(&sha_optimized); - test_sha256_tag_midstate(&sha_optimized, encode_tag, sizeof(encode_tag)); + /* Check that hash initialized by + * secp256k1_ellswift_sha256_init_encode has the expected + * state. */ + secp256k1_ellswift_sha256_init_encode(&sha_optimized); + test_sha256_tag_midstate(&sha_optimized, encode_tag, sizeof(encode_tag)); - /* Check that hash initialized by - * secp256k1_ellswift_sha256_init_create has the expected - * state. */ - secp256k1_ellswift_sha256_init_create(&sha_optimized); - test_sha256_tag_midstate(&sha_optimized, create_tag, sizeof(create_tag)); + /* Check that hash initialized by + * secp256k1_ellswift_sha256_init_create has the expected + * state. */ + secp256k1_ellswift_sha256_init_create(&sha_optimized); + test_sha256_tag_midstate(&sha_optimized, create_tag, sizeof(create_tag)); - /* Check that hash initialized by - * secp256k1_ellswift_sha256_init_bip324 has the expected - * state. */ - secp256k1_ellswift_sha256_init_bip324(&sha_optimized); - test_sha256_tag_midstate(&sha_optimized, bip324_tag, sizeof(bip324_tag)); - } + /* Check that hash initialized by + * secp256k1_ellswift_sha256_init_bip324 has the expected + * state. */ + secp256k1_ellswift_sha256_init_bip324(&sha_optimized); + test_sha256_tag_midstate(&sha_optimized, bip324_tag, sizeof(bip324_tag)); } /* --- Test registry --- */ -/* TODO: subdivide test in cases */ static const struct tf_test_entry tests_ellswift[] = { - CASE(ellswift_tests), + CASE1(ellswift_encoding_test_vectors_tests), + CASE1(ellswift_decoding_test_vectors_tests), + CASE1(ellswift_xdh_test_vectors_tests), + CASE1(ellswift_encode_decode_roundtrip_tests), + CASE1(ellswift_create_tests), + CASE1(ellswift_compute_shared_secret_tests), + CASE1(ellswift_xdh_correctness_tests), + CASE1(ellswift_hash_init_tests), }; #endif diff --git a/src/modules/generator/main_impl.h b/src/modules/generator/main_impl.h index c3f1c027b..c58d66fe5 100644 --- a/src/modules/generator/main_impl.h +++ b/src/modules/generator/main_impl.h @@ -38,12 +38,13 @@ const secp256k1_generator *secp256k1_generator_h = &secp256k1_generator_h_intern static void secp256k1_generator_load(secp256k1_ge* ge, const secp256k1_generator* gen) { + secp256k1_fe x, y; int succeed; - succeed = secp256k1_fe_set_b32_limit(&ge->x, &gen->data[0]); + succeed = secp256k1_fe_set_b32_limit(&x, &gen->data[0]); VERIFY_CHECK(succeed != 0); - succeed = secp256k1_fe_set_b32_limit(&ge->y, &gen->data[32]); + succeed = secp256k1_fe_set_b32_limit(&y, &gen->data[32]); VERIFY_CHECK(succeed != 0); - ge->infinity = 0; + secp256k1_ge_set_xy(ge, &x, &y); (void) succeed; } @@ -343,6 +344,9 @@ int secp256k1_pedersen_blind_sum(const secp256k1_context* ctx, unsigned char *bl VERIFY_CHECK(ctx != NULL); ARG_CHECK(blind_out != NULL); ARG_CHECK(blinds != NULL); + for (i = 0; i < n; i++) { + ARG_CHECK(blinds[i] != NULL); + } ARG_CHECK(npositive <= n); (void) ctx; secp256k1_scalar_set_int(&acc, 0); @@ -370,6 +374,12 @@ int secp256k1_pedersen_verify_tally(const secp256k1_context* ctx, const secp256k VERIFY_CHECK(ctx != NULL); ARG_CHECK(!pcnt || (commits != NULL)); ARG_CHECK(!ncnt || (ncommits != NULL)); + for (i = 0; i < pcnt; i++) { + ARG_CHECK(commits[i] != NULL); + } + for (i = 0; i < ncnt; i++) { + ARG_CHECK(ncommits[i] != NULL); + } (void) ctx; secp256k1_gej_set_infinity(&accj); for (i = 0; i < ncnt; i++) { @@ -394,6 +404,10 @@ int secp256k1_pedersen_blind_generator_blind_sum(const secp256k1_context* ctx, c ARG_CHECK(n_total == 0 || generator_blind != NULL); ARG_CHECK(n_total == 0 || blinding_factor != NULL); ARG_CHECK(n_total > n_inputs); + for (i = 0; i < n_total; i++) { + ARG_CHECK(generator_blind[i] != NULL); + ARG_CHECK(blinding_factor[i] != NULL); + } (void) ctx; if (n_total == 0) { diff --git a/src/modules/generator/tests_impl.h b/src/modules/generator/tests_impl.h index c9f60c0f6..14ec95dc9 100644 --- a/src/modules/generator/tests_impl.h +++ b/src/modules/generator/tests_impl.h @@ -227,6 +227,13 @@ static void test_pedersen_api(void) { CHECK_ILLEGAL(CTX, secp256k1_pedersen_blind_generator_blind_sum(CTX, NULL, &blind_ptr, &blind_out_ptr, 1, 0)); CHECK_ILLEGAL(CTX, secp256k1_pedersen_blind_generator_blind_sum(CTX, &val, NULL, &blind_out_ptr, 1, 0)); CHECK_ILLEGAL(CTX, secp256k1_pedersen_blind_generator_blind_sum(CTX, &val, &blind_ptr, NULL, 1, 0)); + /* check that NULL in array of generator_blind pointers is not allowed */ + blind_ptr = NULL; + CHECK_ILLEGAL(CTX, secp256k1_pedersen_blind_generator_blind_sum(CTX, &val, &blind_ptr, &blind_out_ptr, 1, 0)); + blind_ptr = blind; + /* check that NULL in array of blinding_factor pointers is not allowed */ + blind_out_ptr = NULL; + CHECK_ILLEGAL(CTX, secp256k1_pedersen_blind_generator_blind_sum(CTX, &val, &blind_ptr, &blind_out_ptr, 1, 0)); } static void test_pedersen_internal(void) { @@ -264,6 +271,14 @@ static void test_pedersen_internal(void) { secp256k1_scalar_get_b32(&blinds[i * 32], &s); } CHECK(secp256k1_pedersen_blind_sum(CTX, &blinds[(total - 1) * 32], bptr, total - 1, inputs)); + /* check that NULL in array of blind pointers is not allowed */ + for (i = 0; i < total - 1; i++) { + unsigned char blind_out[32]; + const unsigned char *original_ptr = bptr[i]; + bptr[i] = NULL; + CHECK_ILLEGAL(CTX, secp256k1_pedersen_blind_sum(CTX, blind_out, bptr, total - 1, inputs)); + bptr[i] = original_ptr; + } for (i = 0; i < total; i++) { unsigned char result[33]; secp256k1_pedersen_commitment parse; @@ -275,6 +290,20 @@ static void test_pedersen_internal(void) { } CHECK(secp256k1_pedersen_verify_tally(CTX, cptr, inputs, &cptr[inputs], outputs)); CHECK(secp256k1_pedersen_verify_tally(CTX, &cptr[inputs], outputs, cptr, inputs)); + /* check that NULL in array of commits pointers is not allowed */ + for (i = 0; i < inputs; i++) { + const secp256k1_pedersen_commitment *original_ptr = cptr[i]; + cptr[i] = NULL; + CHECK_ILLEGAL(CTX, secp256k1_pedersen_verify_tally(CTX, cptr, inputs, &cptr[inputs], outputs)); + cptr[i] = original_ptr; + } + /* check that NULL in array of ncommits pointers is not allowed */ + for (i = 0; i < outputs; i++) { + const secp256k1_pedersen_commitment *original_ptr = cptr[inputs + i]; + cptr[inputs + i] = NULL; + CHECK_ILLEGAL(CTX, secp256k1_pedersen_verify_tally(CTX, cptr, inputs, &cptr[inputs], outputs)); + cptr[inputs + i] = original_ptr; + } if (inputs > 0 && values[0] > 0) { CHECK(!secp256k1_pedersen_verify_tally(CTX, cptr, inputs - 1, &cptr[inputs], outputs)); } diff --git a/src/modules/musig/keyagg_impl.h b/src/modules/musig/keyagg_impl.h index 0db4fce85..e412a27ec 100644 --- a/src/modules/musig/keyagg_impl.h +++ b/src/modules/musig/keyagg_impl.h @@ -124,18 +124,11 @@ static void secp256k1_musig_keyaggcoef_internal(secp256k1_scalar *r, const unsig } else { secp256k1_sha256 sha; unsigned char buf[33]; - size_t buflen = sizeof(buf); - int ret; secp256k1_musig_keyaggcoef_sha256(&sha); secp256k1_sha256_write(&sha, pks_hash, 32); - ret = secp256k1_eckey_pubkey_serialize(pk, buf, &buflen, 1); -#ifdef VERIFY /* Serialization does not fail since the pk is not the point at infinity * (according to this function's precondition). */ - VERIFY_CHECK(ret && buflen == sizeof(buf)); -#else - (void) ret; -#endif + secp256k1_eckey_pubkey_serialize33(pk, buf); secp256k1_sha256_write(&sha, buf, sizeof(buf)); secp256k1_sha256_finalize(&sha, buf); secp256k1_scalar_set_b32(r, buf, NULL); @@ -184,6 +177,9 @@ int secp256k1_musig_pubkey_agg(const secp256k1_context* ctx, secp256k1_xonly_pub } ARG_CHECK(pubkeys != NULL); ARG_CHECK(n_pubkeys > 0); + for (i = 0; i < n_pubkeys; i++) { + ARG_CHECK(pubkeys[i] != NULL); + } ecmult_data.ctx = ctx; ecmult_data.pks = pubkeys; diff --git a/src/modules/musig/session_impl.h b/src/modules/musig/session_impl.h index d698442ea..d1c64c96b 100644 --- a/src/modules/musig/session_impl.h +++ b/src/modules/musig/session_impl.h @@ -25,15 +25,8 @@ static void secp256k1_musig_ge_serialize_ext(unsigned char *out33, secp256k1_ge* if (secp256k1_ge_is_infinity(ge)) { memset(out33, 0, 33); } else { - int ret; - size_t size = 33; - ret = secp256k1_eckey_pubkey_serialize(ge, out33, &size, 1); -#ifdef VERIFY /* Serialize must succeed because the point is not at infinity */ - VERIFY_CHECK(ret && size == 33); -#else - (void) ret; -#endif + secp256k1_eckey_pubkey_serialize33(ge, out33); } } @@ -76,7 +69,8 @@ static int secp256k1_musig_secnonce_load(const secp256k1_context* ctx, secp256k1 return 1; } -/* If flag is true, invalidate the secnonce; otherwise leave it. Constant-time. */ +/* If flag is 1, invalidate the secnonce; if flag is 0, leave it. + * Constant-time. Flag must be 0 or 1. */ static void secp256k1_musig_secnonce_invalidate(const secp256k1_context* ctx, secp256k1_musig_secnonce *secnonce, int flag) { secp256k1_memczero(secnonce->data, sizeof(secnonce->data), flag); /* The flag argument is usually classified. So, the line above makes the @@ -224,15 +218,8 @@ int secp256k1_musig_pubnonce_serialize(const secp256k1_context* ctx, unsigned ch return 0; } for (i = 0; i < 2; i++) { - int ret; - size_t size = 33; - ret = secp256k1_eckey_pubkey_serialize(&ges[i], &out66[33*i], &size, 1); -#ifdef VERIFY /* serialize must succeed because the point was just loaded */ - VERIFY_CHECK(ret && size == 33); -#else - (void) ret; -#endif + secp256k1_eckey_pubkey_serialize33(&ges[i], &out66[33*i]); } return 1; } @@ -398,11 +385,9 @@ static int secp256k1_musig_nonce_gen_internal(const secp256k1_context* ctx, secp secp256k1_gej nonce_ptj[2]; int i; unsigned char pk_ser[33]; - size_t pk_ser_len = sizeof(pk_ser); unsigned char aggpk_ser[32]; unsigned char *aggpk_ser_ptr = NULL; secp256k1_ge pk; - int pk_serialize_success; int ret = 1; ARG_CHECK(pubnonce != NULL); @@ -429,15 +414,8 @@ static int secp256k1_musig_nonce_gen_internal(const secp256k1_context* ctx, secp if (!secp256k1_pubkey_load(ctx, &pk, pubkey)) { return 0; } - pk_serialize_success = secp256k1_eckey_pubkey_serialize(&pk, pk_ser, &pk_ser_len, 1); - -#ifdef VERIFY /* A pubkey cannot be the point at infinity */ - VERIFY_CHECK(pk_serialize_success); - VERIFY_CHECK(pk_ser_len == sizeof(pk_ser)); -#else - (void) pk_serialize_success; -#endif + secp256k1_eckey_pubkey_serialize33(&pk, pk_ser); secp256k1_nonce_function_musig(k, input_nonce, msg32, seckey, pk_ser, aggpk_ser_ptr, extra_input32); VERIFY_CHECK(!secp256k1_scalar_is_zero(&k[0])); @@ -544,10 +522,15 @@ static int secp256k1_musig_sum_pubnonces(const secp256k1_context* ctx, secp256k1 int secp256k1_musig_nonce_agg(const secp256k1_context* ctx, secp256k1_musig_aggnonce *aggnonce, const secp256k1_musig_pubnonce * const* pubnonces, size_t n_pubnonces) { secp256k1_gej aggnonce_ptsj[2]; secp256k1_ge aggnonce_pts[2]; + size_t i; + VERIFY_CHECK(ctx != NULL); ARG_CHECK(aggnonce != NULL); ARG_CHECK(pubnonces != NULL); ARG_CHECK(n_pubnonces > 0); + for (i = 0; i < n_pubnonces; i++) { + ARG_CHECK(pubnonces[i] != NULL); + } if (!secp256k1_musig_sum_pubnonces(ctx, aggnonce_ptsj, pubnonces, n_pubnonces)) { return 0; @@ -817,6 +800,9 @@ int secp256k1_musig_partial_sig_agg(const secp256k1_context* ctx, unsigned char ARG_CHECK(session != NULL); ARG_CHECK(partial_sigs != NULL); ARG_CHECK(n_sigs > 0); + for (i = 0; i < n_sigs; i++) { + ARG_CHECK(partial_sigs[i] != NULL); + } if (!secp256k1_musig_session_load(ctx, &session_i, session)) { return 0; diff --git a/src/modules/musig/tests_impl.h b/src/modules/musig/tests_impl.h index 49ff03935..b6d459a2c 100644 --- a/src/modules/musig/tests_impl.h +++ b/src/modules/musig/tests_impl.h @@ -208,6 +208,13 @@ static void musig_api_tests(void) { CHECK(secp256k1_musig_pubkey_agg(CTX, &agg_pk, &keyagg_cache, pk_ptr, 2) == 1); CHECK(secp256k1_musig_pubkey_agg(CTX, NULL, &keyagg_cache, pk_ptr, 2) == 1); CHECK(secp256k1_musig_pubkey_agg(CTX, &agg_pk, NULL, pk_ptr, 2) == 1); + /* check that NULL in array of public key pointers is not allowed */ + for (i = 0; i < 2; i++) { + const secp256k1_pubkey *original_ptr = pk_ptr[i]; + pk_ptr[i] = NULL; + CHECK_ILLEGAL(CTX, secp256k1_musig_pubkey_agg(CTX, &agg_pk, NULL, pk_ptr, 2)); + pk_ptr[i] = original_ptr; + } CHECK_ILLEGAL(CTX, secp256k1_musig_pubkey_agg(CTX, &agg_pk, &keyagg_cache, NULL, 2)); CHECK(memcmp_and_randomize(agg_pk.data, zeros132, sizeof(agg_pk.data)) == 0); CHECK_ILLEGAL(CTX, secp256k1_musig_pubkey_agg(CTX, &agg_pk, &keyagg_cache, invalid_pk_ptr2, 2)); @@ -357,6 +364,13 @@ static void musig_api_tests(void) { /** Receive nonces and aggregate **/ CHECK(secp256k1_musig_nonce_agg(CTX, &aggnonce, pubnonce_ptr, 2) == 1); + /* check that NULL in array of public nonce pointers is not allowed */ + for (i = 0; i < 2; i++) { + const secp256k1_musig_pubnonce *original_ptr = pubnonce_ptr[i]; + pubnonce_ptr[i] = NULL; + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_agg(CTX, &aggnonce, pubnonce_ptr, 2)); + pubnonce_ptr[i] = original_ptr; + } CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_agg(CTX, NULL, pubnonce_ptr, 2)); CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_agg(CTX, &aggnonce, NULL, 2)); CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_agg(CTX, &aggnonce, pubnonce_ptr, 0)); @@ -483,6 +497,13 @@ static void musig_api_tests(void) { /** Signature aggregation and verification */ CHECK(secp256k1_musig_partial_sig_agg(CTX, pre_sig, &session, partial_sig_ptr, 2) == 1); + /* check that NULL in array of partial signature pointers is not allowed */ + for (i = 0; i < 2; i++) { + const secp256k1_musig_partial_sig *original_ptr = partial_sig_ptr[i]; + partial_sig_ptr[i] = NULL; + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_agg(CTX, pre_sig, &session, partial_sig_ptr, 2)); + partial_sig_ptr[i] = original_ptr; + } CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_agg(CTX, NULL, &session, partial_sig_ptr, 2)); CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_agg(CTX, pre_sig, NULL, partial_sig_ptr, 2)); CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_agg(CTX, pre_sig, &invalid_session, partial_sig_ptr, 2)); diff --git a/src/modules/rangeproof/borromean_impl.h b/src/modules/rangeproof/borromean_impl.h index 4906ce85f..2fff3c28c 100644 --- a/src/modules/rangeproof/borromean_impl.h +++ b/src/modules/rangeproof/borromean_impl.h @@ -60,7 +60,6 @@ int secp256k1_borromean_verify(secp256k1_scalar *evalues, const unsigned char *e size_t i; size_t j; size_t count; - size_t size; int overflow; VERIFY_CHECK(e0 != NULL); VERIFY_CHECK(s != NULL); @@ -88,12 +87,12 @@ int secp256k1_borromean_verify(secp256k1_scalar *evalues, const unsigned char *e } /* OPT: loop can be hoisted and split to use batch inversion across all the rings; this would make it much faster. */ secp256k1_ge_set_gej_var(&rge, &rgej); - secp256k1_eckey_pubkey_serialize(&rge, tmp, &size, 1); + secp256k1_eckey_pubkey_serialize33(&rge, tmp); if (j != rsizes[i] - 1) { secp256k1_borromean_hash(tmp, m, mlen, tmp, 33, i, j + 1); secp256k1_scalar_set_b32(&ens, tmp, &overflow); } else { - secp256k1_sha256_write(&sha256_e0, tmp, size); + secp256k1_sha256_write(&sha256_e0, tmp, 33); } count++; } @@ -115,7 +114,6 @@ int secp256k1_borromean_sign(const secp256k1_ecmult_gen_context *ecmult_gen_ctx, size_t i; size_t j; size_t count; - size_t size; int overflow; VERIFY_CHECK(ecmult_gen_ctx != NULL); VERIFY_CHECK(e0 != NULL); @@ -136,7 +134,7 @@ int secp256k1_borromean_sign(const secp256k1_ecmult_gen_context *ecmult_gen_ctx, if (secp256k1_gej_is_infinity(&rgej)) { return 0; } - secp256k1_eckey_pubkey_serialize(&rge, tmp, &size, 1); + secp256k1_eckey_pubkey_serialize33(&rge, tmp); for (j = secidx[i] + 1; j < rsizes[i]; j++) { secp256k1_borromean_hash(tmp, m, mlen, tmp, 33, i, j); secp256k1_scalar_set_b32(&ens, tmp, &overflow); @@ -152,9 +150,9 @@ int secp256k1_borromean_sign(const secp256k1_ecmult_gen_context *ecmult_gen_ctx, return 0; } secp256k1_ge_set_gej_var(&rge, &rgej); - secp256k1_eckey_pubkey_serialize(&rge, tmp, &size, 1); + secp256k1_eckey_pubkey_serialize33(&rge, tmp); } - secp256k1_sha256_write(&sha256_e0, tmp, size); + secp256k1_sha256_write(&sha256_e0, tmp, 33); count += rsizes[i]; } secp256k1_sha256_write(&sha256_e0, m, mlen); @@ -174,7 +172,7 @@ int secp256k1_borromean_sign(const secp256k1_ecmult_gen_context *ecmult_gen_ctx, return 0; } secp256k1_ge_set_gej_var(&rge, &rgej); - secp256k1_eckey_pubkey_serialize(&rge, tmp, &size, 1); + secp256k1_eckey_pubkey_serialize33(&rge, tmp); secp256k1_borromean_hash(tmp, m, mlen, tmp, 33, i, j + 1); secp256k1_scalar_set_b32(&ens, tmp, &overflow); if (overflow || secp256k1_scalar_is_zero(&ens)) { diff --git a/src/modules/whitelist/whitelist_impl.h b/src/modules/whitelist/whitelist_impl.h index bb244907f..edb90b4f7 100644 --- a/src/modules/whitelist/whitelist_impl.h +++ b/src/modules/whitelist/whitelist_impl.h @@ -18,9 +18,10 @@ static int secp256k1_whitelist_hash_pubkey(secp256k1_scalar* output, secp256k1_g secp256k1_ge_set_gej(&ge, pubkey); secp256k1_sha256_initialize(&sha); - if (!secp256k1_eckey_pubkey_serialize(&ge, c, &size, 1)) { + if (secp256k1_ge_is_infinity(&ge)) { return 0; } + secp256k1_eckey_pubkey_serialize33(&ge, c); secp256k1_sha256_write(&sha, c, size); secp256k1_sha256_finalize(&sha, h); secp256k1_sha256_clear(&sha); @@ -95,9 +96,7 @@ static int secp256k1_whitelist_compute_keys_and_message(const secp256k1_context* secp256k1_pubkey_load(ctx, &subkey_ge, sub_pubkey); /* commit to sub-key */ - if (!secp256k1_eckey_pubkey_serialize(&subkey_ge, c, &size, 1)) { - return 0; - } + secp256k1_eckey_pubkey_serialize33(&subkey_ge, c); secp256k1_sha256_write(&sha, c, size); for (i = 0; i < n_keys; i++) { secp256k1_ge offline_ge; @@ -106,14 +105,10 @@ static int secp256k1_whitelist_compute_keys_and_message(const secp256k1_context* /* commit to fixed keys */ secp256k1_pubkey_load(ctx, &offline_ge, &offline_pubkeys[i]); - if (!secp256k1_eckey_pubkey_serialize(&offline_ge, c, &size, 1)) { - return 0; - } + secp256k1_eckey_pubkey_serialize33(&offline_ge, c); secp256k1_sha256_write(&sha, c, size); secp256k1_pubkey_load(ctx, &online_ge, &online_pubkeys[i]); - if (!secp256k1_eckey_pubkey_serialize(&online_ge, c, &size, 1)) { - return 0; - } + secp256k1_eckey_pubkey_serialize33(&online_ge, c); secp256k1_sha256_write(&sha, c, size); /* compute tweaked keys */ diff --git a/src/scalar.h b/src/scalar.h index e75a0cb85..4dd20a692 100644 --- a/src/scalar.h +++ b/src/scalar.h @@ -51,7 +51,7 @@ static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar* /** Add two scalars together (modulo the group order). Returns whether it overflowed. */ static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b); -/** Conditionally add a power of two to a scalar. The result is not allowed to overflow. */ +/** Conditionally add a power of two to a scalar. The result is not allowed to overflow. Flag must be 0 or 1. */ static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag); /** Multiply two scalars (modulo the group order). */ @@ -84,7 +84,7 @@ static int secp256k1_scalar_is_even(const secp256k1_scalar *a); /** Check whether a scalar is higher than the group order divided by 2. */ static int secp256k1_scalar_is_high(const secp256k1_scalar *a); -/** Conditionally negate a number, in constant time. +/** Conditionally negate a number, in constant time. Flag must be 0 or 1. * Returns -1 if the number was negated, 1 otherwise */ static int secp256k1_scalar_cond_negate(secp256k1_scalar *a, int flag); @@ -101,7 +101,7 @@ static void secp256k1_scalar_split_lambda(secp256k1_scalar * SECP256K1_RESTRICT /** 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); -/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized.*/ +/** If flag is 1, set *r equal to *a; if flag is 0, leave it. Constant-time. Both *r and *a must be initialized. Flag must be 0 or 1. */ static void secp256k1_scalar_cmov(secp256k1_scalar *r, const secp256k1_scalar *a, int flag); /** Check invariants on a scalar (no-op unless VERIFY is enabled). */ diff --git a/src/scalar_4x64_impl.h b/src/scalar_4x64_impl.h index 77179f4c6..0f62ee7af 100644 --- a/src/scalar_4x64_impl.h +++ b/src/scalar_4x64_impl.h @@ -130,6 +130,7 @@ static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag) { secp256k1_uint128 t; volatile int vflag = flag; + VERIFY_CHECK(flag == 0 || flag == 1); SECP256K1_SCALAR_VERIFY(r); VERIFY_CHECK(bit < 256); @@ -269,6 +270,7 @@ static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) { uint64_t mask = -vflag; uint64_t nonzero = (secp256k1_scalar_is_zero(r) != 0) - 1; secp256k1_uint128 t; + VERIFY_CHECK(flag == 0 || flag == 1); SECP256K1_SCALAR_VERIFY(r); secp256k1_u128_from_u64(&t, r->d[0] ^ mask); @@ -1091,6 +1093,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; volatile int vflag = flag; + VERIFY_CHECK(flag == 0 || flag == 1); SECP256K1_SCALAR_VERIFY(a); SECP256K1_CHECKMEM_CHECK_VERIFY(r->d, sizeof(r->d)); diff --git a/src/scalar_8x32_impl.h b/src/scalar_8x32_impl.h index 3d1438624..11ae4b45f 100644 --- a/src/scalar_8x32_impl.h +++ b/src/scalar_8x32_impl.h @@ -162,6 +162,7 @@ static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag) { uint64_t t; volatile int vflag = flag; + VERIFY_CHECK(flag == 0 || flag == 1); SECP256K1_SCALAR_VERIFY(r); VERIFY_CHECK(bit < 256); @@ -329,6 +330,7 @@ static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) { uint32_t mask = -vflag; uint32_t nonzero = 0xFFFFFFFFUL * (secp256k1_scalar_is_zero(r) == 0); uint64_t t = (uint64_t)(r->d[0] ^ mask) + ((SECP256K1_N_0 + 1) & mask); + VERIFY_CHECK(flag == 0 || flag == 1); SECP256K1_SCALAR_VERIFY(r); r->d[0] = t & nonzero; t >>= 32; @@ -813,6 +815,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; volatile int vflag = flag; + VERIFY_CHECK(flag == 0 || flag == 1); SECP256K1_SCALAR_VERIFY(a); SECP256K1_CHECKMEM_CHECK_VERIFY(r->d, sizeof(r->d)); diff --git a/src/scalar_low_impl.h b/src/scalar_low_impl.h index d09d8acf6..6b401d371 100644 --- a/src/scalar_low_impl.h +++ b/src/scalar_low_impl.h @@ -62,6 +62,7 @@ static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag) { SECP256K1_SCALAR_VERIFY(r); + VERIFY_CHECK(flag == 0 || flag == 1); if (flag && bit < 32) *r += ((uint32_t)1 << bit); @@ -127,6 +128,7 @@ static int secp256k1_scalar_is_high(const secp256k1_scalar *a) { static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) { SECP256K1_SCALAR_VERIFY(r); + VERIFY_CHECK(flag == 0 || flag == 1); if (flag) secp256k1_scalar_negate(r, r); @@ -167,6 +169,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; volatile int vflag = flag; + VERIFY_CHECK(flag == 0 || flag == 1); SECP256K1_SCALAR_VERIFY(a); SECP256K1_CHECKMEM_CHECK_VERIFY(r, sizeof(*r)); diff --git a/src/secp256k1.c b/src/secp256k1.c index e20ac29d5..69bc9d945 100644 --- a/src/secp256k1.c +++ b/src/secp256k1.c @@ -289,7 +289,6 @@ int secp256k1_ec_pubkey_parse(const secp256k1_context* ctx, secp256k1_pubkey* pu int secp256k1_ec_pubkey_serialize(const secp256k1_context* ctx, unsigned char *output, size_t *outputlen, const secp256k1_pubkey* pubkey, unsigned int flags) { secp256k1_ge Q; size_t len; - int ret = 0; VERIFY_CHECK(ctx != NULL); ARG_CHECK(outputlen != NULL); @@ -301,12 +300,16 @@ int secp256k1_ec_pubkey_serialize(const secp256k1_context* ctx, unsigned char *o ARG_CHECK(pubkey != NULL); ARG_CHECK((flags & SECP256K1_FLAGS_TYPE_MASK) == SECP256K1_FLAGS_TYPE_COMPRESSION); if (secp256k1_pubkey_load(ctx, &Q, pubkey)) { - ret = secp256k1_eckey_pubkey_serialize(&Q, output, &len, !!(flags & SECP256K1_FLAGS_BIT_COMPRESSION)); - if (ret) { - *outputlen = len; + if (flags & SECP256K1_FLAGS_BIT_COMPRESSION) { + secp256k1_eckey_pubkey_serialize33(&Q, output); + *outputlen = 33; + } else { + secp256k1_eckey_pubkey_serialize65(&Q, output); + *outputlen = 65; } + return 1; } - return ret; + return 0; } int secp256k1_ec_pubkey_cmp(const secp256k1_context* ctx, const secp256k1_pubkey* pubkey0, const secp256k1_pubkey* pubkey1) { @@ -342,8 +345,13 @@ static int secp256k1_ec_pubkey_sort_cmp(const void* pk1, const void* pk2, void * } int secp256k1_ec_pubkey_sort(const secp256k1_context* ctx, const secp256k1_pubkey **pubkeys, size_t n_pubkeys) { + size_t i; + VERIFY_CHECK(ctx != NULL); ARG_CHECK(pubkeys != NULL); + for (i = 0; i < n_pubkeys; i++) { + ARG_CHECK(pubkeys[i] != NULL); + } /* Suppress wrong warning (fixed in MSVC 19.33) */ #if defined(_MSC_VER) && (_MSC_VER < 1933) @@ -850,15 +858,7 @@ static void secp256k1_ge_serialize_ext(unsigned char *out33, secp256k1_ge* ge) { if (secp256k1_ge_is_infinity(ge)) { memset(out33, 0, 33); } else { - int ret; - size_t size = 33; - ret = secp256k1_eckey_pubkey_serialize(ge, out33, &size, 1); -#ifdef VERIFY - /* Serialize must succeed because the point is not at infinity */ - VERIFY_CHECK(ret && size == 33); -#else - (void) ret; -#endif + secp256k1_eckey_pubkey_serialize33(ge, out33); } } diff --git a/src/tests.c b/src/tests.c index 7c1a03f8f..6a8b34913 100644 --- a/src/tests.c +++ b/src/tests.c @@ -4291,9 +4291,9 @@ static void test_group_decompress(const secp256k1_fe* x) { secp256k1_fe_normalize_var(&ge_even.y); /* No infinity allowed. */ - CHECK(!ge_quad.infinity); - CHECK(!ge_even.infinity); - CHECK(!ge_odd.infinity); + CHECK(!secp256k1_ge_is_infinity(&ge_quad)); + CHECK(!secp256k1_ge_is_infinity(&ge_even)); + CHECK(!secp256k1_ge_is_infinity(&ge_odd)); /* Check that the x coordinates check out. */ CHECK(secp256k1_fe_equal(&ge_quad.x, x)); @@ -4477,8 +4477,6 @@ static void test_point_times_order(const secp256k1_gej *point) { secp256k1_scalar nx; secp256k1_gej res1, res2; secp256k1_ge res3; - unsigned char pub[65]; - size_t psize = 65; testutil_random_scalar_order_test(&x); secp256k1_scalar_negate(&nx, &x); secp256k1_ecmult(&res1, point, &x, &x); /* calc res1 = x * point + x * G; */ @@ -4488,9 +4486,6 @@ static void test_point_times_order(const secp256k1_gej *point) { secp256k1_ge_set_gej(&res3, &res1); CHECK(secp256k1_ge_is_infinity(&res3)); CHECK(secp256k1_ge_is_valid_var(&res3) == 0); - CHECK(secp256k1_eckey_pubkey_serialize(&res3, pub, &psize, 0) == 0); - psize = 65; - CHECK(secp256k1_eckey_pubkey_serialize(&res3, pub, &psize, 1) == 0); /* check zero/one edge cases */ secp256k1_ecmult(&res1, point, &secp256k1_scalar_zero, &secp256k1_scalar_zero); secp256k1_ge_set_gej(&res3, &res1); @@ -5597,7 +5592,6 @@ static void test_ecmult_accumulate(secp256k1_sha256* acc, const secp256k1_scalar secp256k1_gej rj1, rj2, rj3, rj4, rj5, rj6, gj, infj; secp256k1_ge r; unsigned char bytes[65]; - size_t size = 65; secp256k1_gej_set_ge(&gj, &secp256k1_ge_const_g); secp256k1_gej_set_infinity(&infj); secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &rj1, x); @@ -5618,9 +5612,8 @@ static void test_ecmult_accumulate(secp256k1_sha256* acc, const secp256k1_scalar secp256k1_sha256_write(acc, zerobyte, 1); } else { /* Store other points using their uncompressed serialization. */ - secp256k1_eckey_pubkey_serialize(&r, bytes, &size, 0); - CHECK(size == 65); - secp256k1_sha256_write(acc, bytes, size); + secp256k1_eckey_pubkey_serialize65(&r, bytes); + secp256k1_sha256_write(acc, bytes, sizeof(bytes)); } } @@ -6221,6 +6214,7 @@ static void run_eckey_edge_case_test(void) { secp256k1_pubkey pubkey_negone; const secp256k1_pubkey *pubkeys[3]; size_t len; + int i; /* Group order is too large, reject. */ CHECK(secp256k1_ec_seckey_verify(CTX, orderc) == 0); SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); @@ -6414,6 +6408,14 @@ static void run_eckey_edge_case_test(void) { CHECK(secp256k1_ec_pubkey_combine(CTX, &pubkey, pubkeys, 3) == 1); SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(secp256k1_pubkey)); CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); + /* check that NULL in array of pubkey pointers is not allowed */ + for (i = 0; i < 3; i++) { + const secp256k1_pubkey *original_ptr = pubkeys[i]; + secp256k1_pubkey result; + pubkeys[i] = NULL; + CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_combine(CTX, &result, pubkeys, 3)); + pubkeys[i] = original_ptr; + } len = 33; CHECK(secp256k1_ec_pubkey_serialize(CTX, ctmp, &len, &pubkey, SECP256K1_EC_COMPRESSED) == 1); CHECK(secp256k1_ec_pubkey_serialize(CTX, ctmp2, &len, &pubkey_one, SECP256K1_EC_COMPRESSED) == 1); @@ -6705,16 +6707,18 @@ static void test_random_pubkeys(void) { size_t size = len; firstb = in[0]; /* If the pubkey can be parsed, it should round-trip... */ - CHECK(secp256k1_eckey_pubkey_serialize(&elem, out, &size, len == 33)); - CHECK(size == len); + if (len == 33) { + secp256k1_eckey_pubkey_serialize33(&elem, out); + } else { + secp256k1_eckey_pubkey_serialize65(&elem, out); + } CHECK(secp256k1_memcmp_var(&in[1], &out[1], len-1) == 0); /* ... except for the type of hybrid inputs. */ if ((in[0] != 6) && (in[0] != 7)) { CHECK(in[0] == out[0]); } size = 65; - CHECK(secp256k1_eckey_pubkey_serialize(&elem, in, &size, 0)); - CHECK(size == 65); + secp256k1_eckey_pubkey_serialize65(&elem, in); CHECK(secp256k1_eckey_pubkey_parse(&elem2, in, size)); CHECK(secp256k1_ge_eq_var(&elem2, &elem)); /* Check that the X9.62 hybrid type is checked. */ @@ -6729,7 +6733,7 @@ static void test_random_pubkeys(void) { } if (res) { CHECK(secp256k1_ge_eq_var(&elem, &elem2)); - CHECK(secp256k1_eckey_pubkey_serialize(&elem, out, &size, 0)); + secp256k1_eckey_pubkey_serialize65(&elem, out); CHECK(secp256k1_memcmp_var(&in[1], &out[1], 64) == 0); } } @@ -6807,6 +6811,7 @@ static void permute(size_t *arr, size_t n) { static void test_sort_api(void) { secp256k1_pubkey pks[2]; const secp256k1_pubkey *pks_ptr[2]; + int i; pks_ptr[0] = &pks[0]; pks_ptr[1] = &pks[1]; @@ -6815,6 +6820,13 @@ static void test_sort_api(void) { testutil_random_pubkey_test(&pks[1]); CHECK(secp256k1_ec_pubkey_sort(CTX, pks_ptr, 2) == 1); + /* check that NULL in array of public key pointers is not allowed */ + for (i = 0; i < 2; i++) { + const secp256k1_pubkey *original_ptr = pks_ptr[i]; + pks_ptr[i] = NULL; + CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_sort(CTX, pks_ptr, 2)); + pks_ptr[i] = original_ptr; + } CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_sort(CTX, NULL, 2)); CHECK(secp256k1_ec_pubkey_sort(CTX, pks_ptr, 0) == 1); /* Test illegal public keys */ diff --git a/src/tests_exhaustive.c b/src/tests_exhaustive.c index f8bbcaaf5..13bda6119 100644 --- a/src/tests_exhaustive.c +++ b/src/tests_exhaustive.c @@ -103,9 +103,11 @@ static void test_exhaustive_addition(const secp256k1_ge *group, const secp256k1_ secp256k1_gej_add_ge_var(&tmp, &groupj[i], &group[j], NULL); CHECK(secp256k1_gej_eq_ge_var(&tmp, &group[(i + j) % EXHAUSTIVE_TEST_ORDER])); /* add_zinv_var */ - zless_gej.infinity = groupj[j].infinity; - zless_gej.x = groupj[j].x; - zless_gej.y = groupj[j].y; + if (secp256k1_gej_is_infinity(&groupj[j])) { + secp256k1_ge_set_infinity(&zless_gej); + } else { + secp256k1_ge_set_xy(&zless_gej, &groupj[j].x, &groupj[j].y); + } secp256k1_gej_add_zinv_var(&tmp, &groupj[i], &zless_gej, &fe_inv); CHECK(secp256k1_gej_eq_ge_var(&tmp, &group[(i + j) % EXHAUSTIVE_TEST_ORDER])); } @@ -422,10 +424,8 @@ int main(int argc, char** argv) { secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &generatedj, &scalar_i); secp256k1_ge_set_gej(&generated, &generatedj); - CHECK(group[i].infinity == 0); - CHECK(generated.infinity == 0); - CHECK(secp256k1_fe_equal(&generated.x, &group[i].x)); - CHECK(secp256k1_fe_equal(&generated.y, &group[i].y)); + CHECK(!secp256k1_ge_is_infinity(&group[i])); + CHECK(secp256k1_ge_eq_var(&group[i], &generated)); } } diff --git a/src/testutil.h b/src/testutil.h index 480f6a1a0..93ee3d58b 100644 --- a/src/testutil.h +++ b/src/testutil.h @@ -96,17 +96,13 @@ static void testutil_random_ge_test(secp256k1_ge *ge) { break; } } while(1); - ge->infinity = 0; } static void testutil_random_ge_jacobian_test(secp256k1_gej *gej, const secp256k1_ge *ge) { - secp256k1_fe z2, z3; - testutil_random_fe_non_zero_test(&gej->z); - secp256k1_fe_sqr(&z2, &gej->z); - secp256k1_fe_mul(&z3, &z2, &gej->z); - secp256k1_fe_mul(&gej->x, &ge->x, &z2); - secp256k1_fe_mul(&gej->y, &ge->y, &z3); - gej->infinity = ge->infinity; + secp256k1_fe z; + testutil_random_fe_non_zero_test(&z); + secp256k1_gej_set_ge(gej, ge); + secp256k1_gej_rescale(gej, &z); } static void testutil_random_gej_test(secp256k1_gej *gej) { diff --git a/src/unit_test.h b/src/unit_test.h index bf301e539..d3b0f1538 100644 --- a/src/unit_test.h +++ b/src/unit_test.h @@ -13,7 +13,7 @@ /* Maximum number of command-line arguments. * Must be at least as large as the total number of tests * to allow specifying all tests individually. */ -#define MAX_ARGS 150 +#define MAX_ARGS 200 /* Maximum number of parallel jobs */ #define MAX_SUBPROCESSES 16 diff --git a/src/util.h b/src/util.h index d1fd78438..3a468101b 100644 --- a/src/util.h +++ b/src/util.h @@ -238,6 +238,7 @@ static SECP256K1_INLINE void secp256k1_memczero(void *s, size_t len, int flag) { take only be 0 or 1, which leads to variable time code. */ volatile int vflag = flag; unsigned char mask = -(unsigned char) vflag; + VERIFY_CHECK(flag == 0 || flag == 1); while (len) { *p &= ~mask; p++; @@ -320,7 +321,8 @@ static SECP256K1_INLINE int secp256k1_is_zero_array(const unsigned char *s, size return ret; } -/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized and non-negative.*/ +/** If flag is 1, set *r equal to *a; if flag is 0, leave it. Constant-time. + * Both *r and *a must be initialized and non-negative. Flag must be 0 or 1. */ static SECP256K1_INLINE void secp256k1_int_cmov(int *r, const int *a, int flag) { unsigned int mask0, mask1, r_masked, a_masked; /* Access flag with a volatile-qualified lvalue. @@ -328,6 +330,7 @@ static SECP256K1_INLINE void secp256k1_int_cmov(int *r, const int *a, int flag) take only be 0 or 1, which leads to variable time code. */ volatile int vflag = flag; + VERIFY_CHECK(flag == 0 || flag == 1); /* Casting a negative int to unsigned and back to int is implementation defined behavior */ VERIFY_CHECK(*r >= 0 && *a >= 0);