diff --git a/src/modules/ecdh/Makefile.am.include b/src/modules/ecdh/Makefile.am.include index 1866053529..81bc627917 100644 --- a/src/modules/ecdh/Makefile.am.include +++ b/src/modules/ecdh/Makefile.am.include @@ -1,5 +1,6 @@ include_HEADERS += include/secp256k1_ecdh.h noinst_HEADERS += src/modules/ecdh/main_impl.h noinst_HEADERS += src/modules/ecdh/tests_impl.h +noinst_HEADERS += src/modules/ecdh/tests_exhaustive_impl.h noinst_HEADERS += src/modules/ecdh/bench_impl.h noinst_HEADERS += src/wycheproof/ecdh_secp256k1_test.h diff --git a/src/modules/ecdh/tests_exhaustive_impl.h b/src/modules/ecdh/tests_exhaustive_impl.h new file mode 100644 index 0000000000..db31cb2596 --- /dev/null +++ b/src/modules/ecdh/tests_exhaustive_impl.h @@ -0,0 +1,56 @@ +/*********************************************************************** + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_ECDH_TESTS_EXHAUSTIVE_H +#define SECP256K1_MODULE_ECDH_TESTS_EXHAUSTIVE_H + +#include "../../../include/secp256k1_ecdh.h" +#include "main_impl.h" + +static void test_exhaustive_ecdh(const secp256k1_context *ctx, const secp256k1_ge *group) { + int i, j; + unsigned char seckeys[EXHAUSTIVE_TEST_ORDER - 1][32]; + secp256k1_pubkey pubkeys[EXHAUSTIVE_TEST_ORDER - 1]; + + /* Construct key pairs (32-byte secret key, public key object) for the entire group. */ + for (i = 1; i < EXHAUSTIVE_TEST_ORDER; i++) { + secp256k1_scalar scalar; + secp256k1_scalar_set_int(&scalar, i); + secp256k1_scalar_get_b32(seckeys[i - 1], &scalar); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkeys[i - 1], seckeys[i - 1])); + } + + /* Loop over key combinations. */ + for (i = 1; i < EXHAUSTIVE_TEST_ORDER; i++) { + for (j = 1; j < EXHAUSTIVE_TEST_ORDER; j++) { + unsigned char ecdh_result_ij[32]; + unsigned char ecdh_result_ji[32]; + + /* Calculate ECDH(i*G, j) and ECDH(j*G, i) using API function and verify that the results match. */ + CHECK(secp256k1_ecdh(ctx, ecdh_result_ij, &pubkeys[i - 1], seckeys[j - 1], NULL, NULL)); + CHECK(secp256k1_ecdh(ctx, ecdh_result_ji, &pubkeys[j - 1], seckeys[i - 1], NULL, NULL)); + CHECK(secp256k1_memcmp_var(ecdh_result_ij, ecdh_result_ji, 32) == 0); + + /* Recalculate the expected ECDH result manually by invoking the default ECDH hash + * function on the precomputed group element (groups[i * j]) coordinates, and verify + * that it matches the previously calculated public API results. */ + { + secp256k1_ge ecdh_ge_expected = group[(i * j) % EXHAUSTIVE_TEST_ORDER]; + unsigned char ecdh_result_expected[32]; + unsigned char x[32]; + unsigned char y[32]; + + secp256k1_fe_normalize_var(&ecdh_ge_expected.x); + secp256k1_fe_normalize_var(&ecdh_ge_expected.y); + secp256k1_fe_get_b32(x, &ecdh_ge_expected.x); + secp256k1_fe_get_b32(y, &ecdh_ge_expected.y); + CHECK(secp256k1_ecdh_hash_function_default(ecdh_result_expected, x, y, NULL)); + CHECK(secp256k1_memcmp_var(ecdh_result_ij, ecdh_result_expected, 32) == 0); + } + } + } +} + +#endif diff --git a/src/tests_exhaustive.c b/src/tests_exhaustive.c index 68d4bec3f0..6d128bcca7 100644 --- a/src/tests_exhaustive.c +++ b/src/tests_exhaustive.c @@ -337,6 +337,10 @@ static void test_exhaustive_sign(const secp256k1_context *ctx, const secp256k1_g */ } +#ifdef ENABLE_MODULE_ECDH +#include "modules/ecdh/tests_exhaustive_impl.h" +#endif + #ifdef ENABLE_MODULE_RECOVERY #include "modules/recovery/tests_exhaustive_impl.h" #endif @@ -437,6 +441,9 @@ int main(int argc, char** argv) { test_exhaustive_sign(ctx, group); test_exhaustive_verify(ctx, group); +#ifdef ENABLE_MODULE_ECDH + test_exhaustive_ecdh(ctx, group); +#endif #ifdef ENABLE_MODULE_RECOVERY test_exhaustive_recovery(ctx, group); #endif