diff --git a/.gitmodules b/.gitmodules index 97a855bd..57896bbb 100644 --- a/.gitmodules +++ b/.gitmodules @@ -12,3 +12,6 @@ [submodule "contrib/jwt-cpp"] path = contrib/jwt-cpp url = https://github.com/Thalhammer/jwt-cpp.git +[submodule "contrib/bitcoin-secp256k1"] + path = contrib/bitcoin-secp256k1 + url = https://github.com/bitcoin-core/secp256k1.git diff --git a/contrib/CMakeLists.txt b/contrib/CMakeLists.txt index abfc4885..c1a5535f 100644 --- a/contrib/CMakeLists.txt +++ b/contrib/CMakeLists.txt @@ -5,6 +5,14 @@ add_subdirectory(zlib) add_subdirectory(db) add_subdirectory(ethereum) +option(SECP256K1_BUILD_BENCHMARK "Build benchmarks." OFF) +option(SECP256K1_BUILD_TESTS "Build tests." OFF) +option(SECP256K1_BUILD_EXHAUSTIVE_TESTS "Build exhaustive tests." OFF) +option(SECP256K1_BUILD_CTIME_TESTS "Build constant-time tests." OFF) +option(SECP256K1_BUILD_EXAMPLES "Build examples." OFF) +set_property(GLOBAL PROPERTY CTEST_TARGETS_ADDED 1) +add_subdirectory(bitcoin-secp256k1) + if( NOT DISABLE_TOR) add_subdirectory(tor-connect) endif() @@ -23,6 +31,9 @@ set_property(TARGET libminiupnpc-static PROPERTY FOLDER "contrib") set_property(TARGET zlibstatic PROPERTY FOLDER "contrib") set_property(TARGET mdbx PROPERTY FOLDER "contrib") set_property(TARGET lmdb PROPERTY FOLDER "contrib") +set_property(TARGET secp256k1 PROPERTY FOLDER "contrib") +set_property(TARGET secp256k1_precomputed PROPERTY FOLDER "contrib") + if( NOT DISABLE_TOR) set_property(TARGET tor-connect PROPERTY FOLDER "contrib") endif() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 200096f3..563b4266 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -116,6 +116,8 @@ else() endif() add_library(crypto ${CRYPTO}) +add_dependencies(crypto secp256k1) +target_link_libraries(crypto secp256k1) add_library(currency_core ${CURRENCY_CORE}) add_dependencies(currency_core version ${PCH_LIB_NAME}) diff --git a/tests/functional_tests/crypto_tests.cpp b/tests/functional_tests/crypto_tests.cpp index 546fff99..6cd876b5 100644 --- a/tests/functional_tests/crypto_tests.cpp +++ b/tests/functional_tests/crypto_tests.cpp @@ -1896,6 +1896,66 @@ TEST(crypto, generators_precomp) #undef CHECK_PRECOMP } +#include "bitcoin-secp256k1/include/secp256k1.h" +TEST(crypto, secp256k1_ecdsa_native) +{ + bool r = false; + + secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); + uint8_t randomness[32]; + crypto::generate_random_bytes(sizeof randomness, randomness); + secp256k1_context_randomize(ctx, randomness); + + uint8_t seckey[32] = {}; + while(true) + { + crypto::generate_random_bytes(sizeof seckey, seckey); + if (secp256k1_ec_seckey_verify(ctx, seckey)) + break; + } + + secp256k1_pubkey pubkey{}; + ASSERT_TRUE(secp256k1_ec_pubkey_create(ctx, &pubkey, seckey)); + + uint8_t compressed_pubkey[33] = {}; + size_t output_len = sizeof compressed_pubkey; + ASSERT_TRUE(secp256k1_ec_pubkey_serialize(ctx, compressed_pubkey, &output_len, &pubkey, SECP256K1_EC_COMPRESSED)); + ASSERT_TRUE(output_len == sizeof compressed_pubkey); + + + secp256k1_ecdsa_signature secp256k1_ecdsa_sig{}; + hash msg_hash = hash_helper_t::h("message"); + ASSERT_TRUE(secp256k1_ecdsa_sign(ctx, &secp256k1_ecdsa_sig, (const unsigned char*)&msg_hash, seckey, NULL, NULL)); + + // Serialize the signature in a compact form. + unsigned char secp256k1_ecdsa_sig_serialized[64] = {}; + ASSERT_TRUE(secp256k1_ecdsa_signature_serialize_compact(ctx, secp256k1_ecdsa_sig_serialized, &secp256k1_ecdsa_sig)); + + // + // Verification + // + + secp256k1_ecdsa_sig = secp256k1_ecdsa_signature{}; + pubkey = secp256k1_pubkey{}; + + // Deserialize the signature. + ASSERT_TRUE(secp256k1_ecdsa_signature_parse_compact(ctx, &secp256k1_ecdsa_sig, secp256k1_ecdsa_sig_serialized)); + + // Deserialize the public key. This will return 0 if the public key can't be parsed correctly. */ + ASSERT_TRUE(secp256k1_ec_pubkey_parse(ctx, &pubkey, compressed_pubkey, sizeof(compressed_pubkey))); + + // verify a signature + ASSERT_TRUE(secp256k1_ecdsa_verify(ctx, &secp256k1_ecdsa_sig, (const unsigned char*)&msg_hash, &pubkey)); + + // verify using a static context + ASSERT_TRUE(secp256k1_ecdsa_verify(secp256k1_context_static, &secp256k1_ecdsa_sig, (const unsigned char*)&msg_hash, &pubkey)); + + + // Epilogue + secp256k1_context_destroy(ctx); + return true; +} + //