diff --git a/Makefile.am b/Makefile.am index 122e044cea..9faf72322d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -49,6 +49,7 @@ 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/cli_util.h noinst_HEADERS += src/int128.h noinst_HEADERS += src/int128_impl.h noinst_HEADERS += src/int128_native.h diff --git a/src/bench.c b/src/bench.c index 833f70718b..f4e2cea099 100644 --- a/src/bench.c +++ b/src/bench.c @@ -9,6 +9,7 @@ #include "../include/secp256k1.h" #include "util.h" +#include "cli_util.h" #include "bench.h" static void help(int default_iters) { diff --git a/src/bench.h b/src/bench.h index bf9a932ff4..a9c829da63 100644 --- a/src/bench.h +++ b/src/bench.h @@ -10,7 +10,6 @@ #include #include #include -#include #if (defined(_MSC_VER) && _MSC_VER >= 1900) # include @@ -79,7 +78,7 @@ static void print_number(const int64_t x) { y /= 10; } } else if (c == 0) { /* fractional part is 0 */ - buffer[--ptr] = '0'; + buffer[--ptr] = '0'; } buffer[--ptr] = '.'; do { @@ -129,44 +128,6 @@ static void run_benchmark(char *name, void (*benchmark)(void*, int), void (*setu printf("\n"); } -static int have_flag(int argc, char** argv, char *flag) { - char** argm = argv + argc; - argv++; - while (argv != argm) { - if (strcmp(*argv, flag) == 0) { - return 1; - } - argv++; - } - return 0; -} - -/* takes an array containing the arguments that the user is allowed to enter on the command-line - returns: - - 1 if the user entered an invalid argument - - 0 if all the user entered arguments are valid */ -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; - argv++; - - while (argv != argm) { - found_valid = 0; - for (i = 0; i < n; i++) { - if (strcmp(*argv, valid_args[i]) == 0) { - found_valid = 1; /* user entered a valid arg from the list */ - break; - } - } - if (found_valid == 0) { - return 1; /* invalid arg found */ - } - argv++; - } - return 0; -} - static int get_iters(int default_iters) { char* env = getenv("SECP256K1_BENCH_ITERS"); if (env) { diff --git a/src/bench_ecmult.c b/src/bench_ecmult.c index 98fb798d82..38f768cb6d 100644 --- a/src/bench_ecmult.c +++ b/src/bench_ecmult.c @@ -9,6 +9,7 @@ #include "../include/secp256k1.h" #include "util.h" +#include "cli_util.h" #include "hash_impl.h" #include "field_impl.h" #include "group_impl.h" diff --git a/src/bench_internal.c b/src/bench_internal.c index fd794a1c9d..b15124df64 100644 --- a/src/bench_internal.c +++ b/src/bench_internal.c @@ -10,6 +10,7 @@ #include "assumptions.h" #include "util.h" +#include "cli_util.h" #include "hash_impl.h" #include "field_impl.h" #include "group_impl.h" diff --git a/src/cli_util.h b/src/cli_util.h new file mode 100644 index 0000000000..0a07499dd5 --- /dev/null +++ b/src/cli_util.h @@ -0,0 +1,50 @@ +/*********************************************************************** + * Copyright (c) 2023 Jonas Nick * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_CLI_UTIL_H +#define SECP256K1_CLI_UTIL_H + +#include + +static int have_flag(int argc, char** argv, char *flag) { + char** argm = argv + argc; + argv++; + while (argv != argm) { + if (strcmp(*argv, flag) == 0) { + return 1; + } + argv++; + } + return 0; +} + +/* takes an array containing the arguments that the user is allowed to enter on the command-line + returns: + - 1 if the user entered an invalid argument + - 0 if all the user entered arguments are valid */ +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; + argv++; + + while (argv != argm) { + found_valid = 0; + for (i = 0; i < n; i++) { + if (strcmp(*argv, valid_args[i]) == 0) { + found_valid = 1; /* user entered a valid arg from the list */ + break; + } + } + if (found_valid == 0) { + return 1; /* invalid arg found */ + } + argv++; + } + return 0; +} + +#endif /* SECP256K1_CLI_UTIL_H */ diff --git a/src/tests.c b/src/tests.c index bc5b7cb1f1..429b0d5aa9 100644 --- a/src/tests.c +++ b/src/tests.c @@ -16,6 +16,7 @@ #include "testrand_impl.h" #include "checkmem.h" #include "util.h" +#include "cli_util.h" #include "../contrib/lax_der_parsing.c" #include "../contrib/lax_der_privatekey_parsing.c" @@ -28,7 +29,8 @@ #define CONDITIONAL_TEST(cnt, nam) if (COUNT < (cnt)) { printf("Skipping %s (iteration count too low)\n", nam); } else -static int COUNT = 64; +#define DEFAULT_COUNT 64 +static int COUNT = DEFAULT_COUNT; static secp256k1_context *CTX = NULL; static secp256k1_context *STATIC_CTX = NULL; @@ -7428,7 +7430,96 @@ static void run_cmov_tests(void) { ge_storage_cmov_test(); } +static int process_args(int *all_enabled, int argc, char **argv) { + int is_count_arg_set = 0; + const char* env = getenv("SECP256K1_TEST_ITERS"); + char* valid_args[] = {"integer", "hash", "scalar", "field", "group", + "ecmult", "ecdh", "ecdsa", "recovery", "extrakeys", + "schnorrsig"}; + size_t valid_args_size = sizeof(valid_args)/sizeof(valid_args[0]); + + if (argc > 1) { + int count_arg = strtol(argv[1], NULL, 0); + if (count_arg > 0) { + is_count_arg_set = 1; + COUNT = count_arg; + } + } + + if (env && strlen(env) > 0) { + COUNT = strtol(env, NULL, 0); + if (is_count_arg_set) { + fputs("Environment variable SECP256K1_TEST_ITERS and command line argument both try to set the iteration count.\n", stderr); + return 0; + } + if (COUNT <= 0) { + fputs("An iteration count of 0 or less is not allowed.\n", stderr); + return 0; + } + } + + *all_enabled = argc == 1 || (argc == 2 && is_count_arg_set); + + if (is_count_arg_set) { + argc--; + argv++; + } + if (have_invalid_args(argc, argv, valid_args, valid_args_size)) { + fprintf(stderr, "./tests: unrecognized argument.\n\n"); + return 0; + } + + return 1; +} + +static int module_unavailable(int argc, char **argv, char *module) { + if (have_flag(argc, argv, module)) { + fprintf(stderr, "./tests: %s module not enabled.\n", module); + fprintf(stderr, "Use ./configure --enable-module-%s.\n\n", module); + return 1; + } + return 0; +} + + +static void help(void) { + printf("The command ./tests runs a test suite on the code base.\n"); + printf("\n"); + printf("Some randomized tests are run for a certain number of iterations,\n"); + printf("which is set to %d by default. This number can be altered by either\n", DEFAULT_COUNT); + printf("setting the environment variable SECP256K1_TEST_ITERS or by providing\n"); + printf("the iteration count as a command line argument.\n"); + printf("\n"); + printf("By default, all tests are enabled.\n"); + printf("Usage: ./tests [args]\n"); + printf("Available arguments:\n"); + printf(" help : display this help message and exit\n"); + printf(" : set the iteration count to \n"); + printf(" integer : enable integer tests\n"); + printf(" hash : enable hash tests\n"); + printf(" scalar : enable scalar tests\n"); + printf(" field : enable field tests\n"); + printf(" group : enable group tests\n"); + printf(" ecmult : enable ecmult tests\n"); +#ifdef ENABLE_MODULE_ECDH + printf(" ecdh : enable ecdh tests\n"); +#endif + printf(" ecdsa : enable ecdsa tests\n"); +#ifdef ENABLE_MODULE_RECOVERY + printf(" recovery : enable recovery tests\n"); +#endif +#ifdef ENABLE_MODULE_EXTRAKEYS + printf(" extrakeys : enable extrakeys tests\n"); +#endif +#ifdef ENABLE_MODULE_SCHNORRSIG + printf(" schnorrsig : enable schnorrsig tests\n"); +#endif + printf("\n"); +} + int main(int argc, char **argv) { + /* This variable is set to true if all tests are enabled by the user */ + int all_enabled; /* Disable buffering for stdout to improve reliability of getting * diagnostic information. Happens right at the start of main because * setbuf must be used before any other operation on the stream. */ @@ -7437,17 +7528,17 @@ int main(int argc, char **argv) { * unbuffered on all systems. */ setbuf(stderr, NULL); - /* find iteration count */ if (argc > 1) { - COUNT = strtol(argv[1], NULL, 0); - } else { - const char* env = getenv("SECP256K1_TEST_ITERS"); - if (env && strlen(env) > 0) { - COUNT = strtol(env, NULL, 0); + if (have_flag(argc, argv, "-h") + || have_flag(argc, argv, "--help") + || have_flag(argc, argv, "help")) { + help(); + return 0; } } - if (COUNT <= 0) { - fputs("An iteration count of 0 or less is not allowed.\n", stderr); + + if (!process_args(&all_enabled, argc, argv)) { + help(); return EXIT_FAILURE; } printf("test count = %i\n", COUNT); @@ -7494,47 +7585,59 @@ int main(int argc, char **argv) { run_rand_int(); /* integer arithmetic tests */ + if (all_enabled || have_flag(argc, argv, "integer")) { #ifdef SECP256K1_WIDEMUL_INT128 - run_int128_tests(); + run_int128_tests(); #endif - run_ctz_tests(); - run_modinv_tests(); - run_inverse_tests(); + run_ctz_tests(); + run_modinv_tests(); + run_inverse_tests(); + } /* hash tests */ - run_sha256_known_output_tests(); - run_sha256_counter_tests(); - run_hmac_sha256_tests(); - run_rfc6979_hmac_sha256_tests(); - run_tagged_sha256_tests(); + if (all_enabled || have_flag(argc, argv, "hash")) { + run_sha256_known_output_tests(); + run_sha256_counter_tests(); + run_hmac_sha256_tests(); + run_rfc6979_hmac_sha256_tests(); + run_tagged_sha256_tests(); + } /* scalar tests */ - run_scalar_tests(); + if (all_enabled || have_flag(argc, argv, "scalar")) { + run_scalar_tests(); + } /* field tests */ - run_field_half(); - run_field_misc(); - run_field_convert(); - run_fe_mul(); - run_sqr(); - run_sqrt(); + if (all_enabled || have_flag(argc, argv, "field")) { + run_field_half(); + run_field_misc(); + run_field_convert(); + run_fe_mul(); + run_sqr(); + run_sqrt(); + } /* group tests */ - run_ge(); - run_gej(); - run_group_decompress(); + if (all_enabled || have_flag(argc, argv, "group")) { + run_ge(); + run_gej(); + run_group_decompress(); + } /* ecmult tests */ - run_ecmult_pre_g(); - run_wnaf(); - run_point_times_order(); - run_ecmult_near_split_bound(); - run_ecmult_chain(); - run_ecmult_constants(); - run_ecmult_gen_blind(); - run_ecmult_const_tests(); - run_ecmult_multi_tests(); - run_ec_combine(); + if (all_enabled || have_flag(argc, argv, "ecmult")) { + run_ecmult_pre_g(); + run_wnaf(); + run_point_times_order(); + run_ecmult_near_split_bound(); + run_ecmult_chain(); + run_ecmult_constants(); + run_ecmult_gen_blind(); + run_ecmult_const_tests(); + run_ecmult_multi_tests(); + run_ec_combine(); + } /* endomorphism tests */ run_endomorphism_tests(); @@ -7550,29 +7653,59 @@ int main(int argc, char **argv) { #ifdef ENABLE_MODULE_ECDH /* ecdh tests */ - run_ecdh_tests(); + if (all_enabled || have_flag(argc, argv, "ecdh")) { + run_ecdh_tests(); + } +#endif +#ifndef ENABLE_MODULE_ECDH + if (module_unavailable(argc, argv, "ecdh")) { + return EXIT_FAILURE; + } #endif /* ecdsa tests */ - run_ec_illegal_argument_tests(); - run_pubkey_comparison(); - run_random_pubkeys(); - run_ecdsa_der_parse(); - run_ecdsa_sign_verify(); - run_ecdsa_end_to_end(); - run_ecdsa_edge_cases(); + if (all_enabled || have_flag(argc, argv, "ecdsa")) { + run_ec_illegal_argument_tests(); + run_pubkey_comparison(); + run_random_pubkeys(); + run_ecdsa_der_parse(); + run_ecdsa_sign_verify(); + run_ecdsa_end_to_end(); + run_ecdsa_edge_cases(); + } #ifdef ENABLE_MODULE_RECOVERY /* ECDSA pubkey recovery tests */ - run_recovery_tests(); + if (all_enabled || have_flag(argc, argv, "recovery")) { + run_recovery_tests(); + } +#endif +#ifndef ENABLE_MODULE_RECOVERY + if (module_unavailable(argc, argv, "recovery")) { + return EXIT_FAILURE; + } #endif #ifdef ENABLE_MODULE_EXTRAKEYS - run_extrakeys_tests(); + if (all_enabled || have_flag(argc, argv, "extrakeys")) { + run_extrakeys_tests(); + } +#endif +#ifndef ENABLE_MODULE_EXTRAKEYS + if (module_unavailable(argc, argv, "extrakeys")) { + return EXIT_FAILURE; + } #endif #ifdef ENABLE_MODULE_SCHNORRSIG - run_schnorrsig_tests(); + if (all_enabled || have_flag(argc, argv, "schnorrsig")) { + run_schnorrsig_tests(); + } +#endif +#ifndef ENABLE_MODULE_SCHNORRSIG + if (module_unavailable(argc, argv, "schnorrsig")) { + return EXIT_FAILURE; + } #endif /* util tests */