diff --git a/src/secp256k1/CMakeLists.txt b/src/secp256k1/CMakeLists.txt index d4f190512..66042c435 100644 --- a/src/secp256k1/CMakeLists.txt +++ b/src/secp256k1/CMakeLists.txt @@ -1,400 +1,400 @@ # Copyright (c) 2017 The Bitcoin developers cmake_minimum_required(VERSION 3.16) project(secp256k1 LANGUAGES C VERSION 0.1.0) # Add path for custom modules when building as a standalone project list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules) # Default to RelWithDebInfo configuration if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "Select the configuration for the build" FORCE) set(__NO_USER_CMAKE_BUILD_TYPE ON CACHE BOOL "True if the user didn't set a build type on the command line") endif() option(SECP256K1_ENABLE_COVERAGE "Enable coverage" OFF) option(SECP256K1_ENABLE_BRANCH_COVERAGE "Enable branch coverage" OFF) include(AddCompilerFlags) if(SECP256K1_ENABLE_COVERAGE) include(Coverage) enable_coverage(${SECP256K1_ENABLE_BRANCH_COVERAGE}) exclude_from_coverage("${CMAKE_CURRENT_SOURCE_DIR}/src/bench") # If no build type is manually defined, override the optimization level. # Otherwise, alert the user than the coverage result might be useless. if(__NO_USER_CMAKE_BUILD_TYPE) set_c_optimization_level(0) else() message(WARNING "It is advised to not enforce CMAKE_BUILD_TYPE to get the best coverage results") endif() set(COVERAGE 1) endif() # libsecp256k1 use a different set of flags. add_c_compiler_flags( -pedantic -Wall -Wextra -Wcast-align -Wshadow -Wundef -Wno-unused-function -Wno-overlength-strings -std=c89 -Wnested-externs -Wstrict-prototypes -Wno-long-long ) # Default visibility is hidden on all targets. set(CMAKE_C_VISIBILITY_PRESET hidden) include_directories( . src # For the config ${CMAKE_CURRENT_BINARY_DIR}/src ) # The library add_library(secp256k1 src/secp256k1.c) target_include_directories(secp256k1 PUBLIC include) set(SECP256K1_PUBLIC_HEADERS include/secp256k1.h include/secp256k1_preallocated.h ) option(SECP256K1_ENABLE_BIGNUM "Use the GMP bignum implementation" OFF) if(SECP256K1_ENABLE_BIGNUM) # We need to link in GMP find_package(GMP REQUIRED) target_link_libraries(secp256k1 GMP::gmp) set(USE_NUM_GMP 1) set(USE_FIELD_INV_NUM 1) set(USE_SCALAR_INV_NUM 1) else() set(USE_NUM_NONE 1) set(USE_FIELD_INV_BUILTIN 1) set(USE_SCALAR_INV_BUILTIN 1) endif() # Guess the target architecture, within the ones with supported ASM. # First check if the CMAKE_C_COMPILER_TARGET is set (should be when # cross compiling), then CMAKE_SYSTEM_PROCESSOR as a fallback if meaningful # (this is not the case for ARM as the content is highly non standard). if(CMAKE_C_COMPILER_TARGET MATCHES "x86_64" OR CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64") set(SECP256K1_ASM_BUILD_TARGET "x86_64") set(SECP256K1_DEFAULT_USE_ASM ON) elseif(CMAKE_C_COMPILER_TARGET MATCHES "arm-linux-gnueabihf") set(SECP256K1_ASM_BUILD_TARGET "arm-linux-gnueabihf") set(SECP256K1_DEFAULT_USE_ASM ON) endif() # Enable ASM by default only if we are building for a compatible target. # The user can still enable/disable it manually if needed. option(SECP256K1_USE_ASM "Use assembly" ${SECP256K1_DEFAULT_USE_ASM}) if(SECP256K1_USE_ASM) macro(unsupported_asm_error) message(FATAL_ERROR "Assembly is enabled, but not supported for your target architecture." "Re-run cmake with -DSECP256K1_USE_ASM=OFF to disable ASM support." ) endmacro() if(SECP256K1_ASM_BUILD_TARGET MATCHES "x86_64") # We check if amd64 asm is supported. check_c_source_compiles(" #include int main() { uint64_t a = 11, tmp; __asm__ __volatile__(\"movq \$0x100000000,%1; mulq %%rsi\" : \"+a\"(a) : \"S\"(tmp) : \"cc\", \"%rdx\"); return 0; } " USE_ASM_X86_64) if(NOT USE_ASM_X86_64) unsupported_asm_error() endif() elseif(SECP256K1_ASM_BUILD_TARGET MATCHES "arm-linux-gnueabihf") enable_language(ASM) set(USE_EXTERNAL_ASM 1) add_library(secp256k1_common src/asm/field_10x26_arm.s) target_link_libraries(secp256k1 secp256k1_common) else() unsupported_asm_error() endif() endif() set(SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY "" CACHE STRING "Test-only override of the (autodetected by the C code) \"widemul\" setting (can be int64 or int128)") if(SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY STREQUAL "int128") message(STATUS "Force the use of the (unsigned) __int128 based wide multiplication implementation") target_compile_definitions(secp256k1 PUBLIC USE_FORCE_WIDEMUL_INT128=1) elseif(SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY STREQUAL "int64") message(STATUS "Force the use of the (u)int64_t based wide multiplication implementation") target_compile_definitions(secp256k1 PUBLIC USE_FORCE_WIDEMUL_INT64=1) endif() option(SECP256K1_BUILD_TEST "Build secp256k1's unit tests" ON) include(CMakeDependentOption) cmake_dependent_option( SECP256K1_BUILD_OPENSSL_TESTS "Build the OpenSSL tests" ON SECP256K1_BUILD_TEST ON ) if(SECP256K1_BUILD_OPENSSL_TESTS) include(BrewHelper) find_brew_prefix(OPENSSL_ROOT_DIR openssl) find_package(OpenSSL COMPONENTS Crypto) if(NOT OpenSSL_FOUND) message(FATAL_ERROR "OpenSSL is not found, but is required for some tests. You can disable them by passing -DSECP256K1_BUILD_OPENSSL_TESTS=OFF." ) endif() set(ENABLE_OPENSSL_TESTS 1) endif() # Executable internal to secp256k1 need to have the HAVE_CONFIG_H define set. # For convenience, we wrap this into a function. function(link_secp256k1_internal NAME) target_link_libraries(${NAME} secp256k1) target_compile_definitions(${NAME} PRIVATE HAVE_CONFIG_H SECP256K1_BUILD) if(SECP256K1_BUILD_OPENSSL_TESTS) target_link_libraries(${NAME} OpenSSL::Crypto) endif() endfunction(link_secp256k1_internal) include(InstallationHelper) # Phony target to build benchmarks add_custom_target(bench-secp256k1) function(add_secp256k1_bench NAME) set(EXECUTABLE_NAME "${NAME}-bench") add_executable(${EXECUTABLE_NAME} ${ARGN}) link_secp256k1_internal(${EXECUTABLE_NAME}) set(BENCH_NAME "bench-secp256k1-${NAME}") add_custom_target(${BENCH_NAME} COMMENT "Benchmarking libsecp256k1 ${NAME}" COMMAND ${EXECUTABLE_NAME} USES_TERMINAL ) add_dependencies(bench-secp256k1 ${BENCH_NAME}) install_target("${EXECUTABLE_NAME}" COMPONENT secp256k1-bench EXCLUDE_FROM_ALL ) endfunction(add_secp256k1_bench) # ECDH module option(SECP256K1_ENABLE_MODULE_ECDH "Build libsecp256k1's ECDH module" OFF) if(SECP256K1_ENABLE_MODULE_ECDH) set(ENABLE_MODULE_ECDH 1) add_secp256k1_bench(ecdh src/bench_ecdh.c) list(APPEND SECP256K1_PUBLIC_HEADERS include/secp256k1_ecdh.h) endif() # MultiSet module option(SECP256K1_ENABLE_MODULE_MULTISET "Build libsecp256k1's MULTISET module" OFF) if(SECP256K1_ENABLE_MODULE_MULTISET) set(ENABLE_MODULE_MULTISET 1) add_secp256k1_bench(multiset src/bench_multiset.c) list(APPEND SECP256K1_PUBLIC_HEADERS include/secp256k1_multiset.h) endif() # Recovery module option(SECP256K1_ENABLE_MODULE_RECOVERY "Build libsecp256k1's recovery module" ON) if(SECP256K1_ENABLE_MODULE_RECOVERY) set(ENABLE_MODULE_RECOVERY 1) add_secp256k1_bench(recover src/bench_recover.c) list(APPEND SECP256K1_PUBLIC_HEADERS include/secp256k1_recovery.h) endif() # Schnorr module option(SECP256K1_ENABLE_MODULE_SCHNORR "Build libsecp256k1's Schnorr module" ON) if(SECP256K1_ENABLE_MODULE_SCHNORR) set(ENABLE_MODULE_SCHNORR 1) list(APPEND SECP256K1_PUBLIC_HEADERS include/secp256k1_schnorr.h) endif() # Extrakeys module option(SECP256K1_ENABLE_MODULE_EXTRAKEYS "Build libsecp256k1's Extrakeys module" OFF) if(SECP256K1_ENABLE_MODULE_EXTRAKEYS) set(ENABLE_MODULE_EXTRAKEYS 1) list(APPEND SECP256K1_PUBLIC_HEADERS include/secp256k1_extrakeys.h) endif() # Schnorrsig module option(SECP256K1_ENABLE_MODULE_SCHNORRSIG "Build libsecp256k1's Schnorrsig module" OFF) if(SECP256K1_ENABLE_MODULE_SCHNORRSIG) if(NOT SECP256K1_ENABLE_MODULE_EXTRAKEYS) message(FATAL_ERROR "The module Schnorrsig require Extrakeys. Try running cmake using -DSECP256K1_ENABLE_MODULE_EXTRAKEYS=On") endif() set(ENABLE_MODULE_SCHNORRSIG 1) add_secp256k1_bench(schnorrsig src/bench_schnorrsig.c) list(APPEND SECP256K1_PUBLIC_HEADERS include/secp256k1_schnorrsig.h) endif() # External default callbacks option(SECP256K1_ENABLE_EXTERNAL_DEFAULT_CALLBACKS "Enable external default callbacks" OFF) if(SECP256K1_ENABLE_EXTERNAL_DEFAULT_CALLBACKS) set(USE_EXTERNAL_DEFAULT_CALLBACKS 1) endif() # Endomorphism -option(SECP256K1_ENABLE_ENDOMORPHISM "Enable endomorphism" OFF) +option(SECP256K1_ENABLE_ENDOMORPHISM "Enable endomorphism" ON) if(SECP256K1_ENABLE_ENDOMORPHISM) set(USE_ENDOMORPHISM 1) endif() # Make the emult window size customizable. set(SECP256K1_ECMULT_WINDOW_SIZE 15 CACHE STRING "Window size for ecmult precomputation for verification, specified as integer in range [2..24].") if(${SECP256K1_ECMULT_WINDOW_SIZE} LESS 2 OR ${SECP256K1_ECMULT_WINDOW_SIZE} GREATER 24) message(FATAL_ERROR "SECP256K1_ECMULT_WINDOW_SIZE must be an integer in range [2..24]") endif() set(SECP256K1_ECMULT_GEN_PRECISION 4 CACHE STRING "Precision bits to tune the precomputed table size for signing.") set(VALID_PRECISIONS 2 4 8) if(NOT ${SECP256K1_ECMULT_GEN_PRECISION} IN_LIST VALID_PRECISIONS) message(FATAL_ERROR "SECP256K1_ECMULT_GEN_PRECISION not 2, 4, 8") endif() # Static precomputation for elliptic curve multiplication option(SECP256K1_ECMULT_STATIC_PRECOMPUTATION "Precompute libsecp256k1's elliptic curve multiplication tables" ON) if(SECP256K1_ECMULT_STATIC_PRECOMPUTATION) set(USE_ECMULT_STATIC_PRECOMPUTATION 1) include(NativeExecutable) native_add_cmake_flags( "-DSECP256K1_ECMULT_WINDOW_SIZE=${SECP256K1_ECMULT_WINDOW_SIZE}" "-DSECP256K1_ECMULT_GEN_PRECISION=${SECP256K1_ECMULT_GEN_PRECISION}" "-DSECP256K1_USE_ASM=OFF" "-DSECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY=${SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY}" "-DSECP256K1_BUILD_OPENSSL_TESTS=OFF" ) add_native_executable(gen_context src/gen_context.c) add_custom_command( OUTPUT src/ecmult_static_context.h COMMAND gen_context ) target_sources(secp256k1 PRIVATE src/ecmult_static_context.h) endif() # If this project is not the top level project, then don't install by default get_directory_property(SECP256K1_PARENT_DIRECTORY PARENT_DIRECTORY) if(SECP256K1_PARENT_DIRECTORY) set(SECP256K1_INSTALL_EXCLUDE_FROM_ALL EXCLUDE_FROM_ALL) endif() if(BUILD_SHARED_LIBS) install_shared_library(secp256k1 PUBLIC_HEADER ${SECP256K1_PUBLIC_HEADERS} ${SECP256K1_INSTALL_EXCLUDE_FROM_ALL} ) else() set_property(TARGET secp256k1 PROPERTY PUBLIC_HEADER ${SECP256K1_PUBLIC_HEADERS}) install_target(secp256k1 ${SECP256K1_INSTALL_EXCLUDE_FROM_ALL}) endif() # Generate the config configure_file(src/libsecp256k1-config.h.cmake.in src/libsecp256k1-config.h ESCAPE_QUOTES) target_compile_definitions(secp256k1 PRIVATE HAVE_CONFIG_H SECP256K1_BUILD) # Build the Java binding option(SECP256K1_ENABLE_JNI "Enable the Java Native Interface binding" OFF) if(SECP256K1_ENABLE_JNI) if(NOT SECP256K1_ENABLE_MODULE_ECDH) message(FATAL_ERROR "The secp256k1 JNI support requires ECDH. Try again with -DSECP256K1_ENABLE_MODULE_ECDH=ON.") endif() find_package(Java REQUIRED) find_package(JNI REQUIRED) include(UseJava) add_library(secp256k1_jni SHARED src/java/org_bitcoin_NativeSecp256k1.c src/java/org_bitcoin_Secp256k1Context.c ) install_shared_library(secp256k1_jni ${SECP256K1_INSTALL_EXCLUDE_FROM_ALL}) target_include_directories(secp256k1_jni PUBLIC ${JNI_INCLUDE_DIRS}) # As per CMake documentation: the POSITION_INDEPENDENT_CODE property is set # when a target is created. It defaults to True for SHARED or MODULE library # targets and False otherwise. # The secp256ki_jni library being shared, the property is set and it will # build with PIC enabled. But the secp256k1 dependency might not have the # property set, so it's associated source files won't be built with PIC # enabled. That would cause the linker to fail. # Forcing the property for the secp256k1 library fixes the issue. set_target_properties(secp256k1 PROPERTIES POSITION_INDEPENDENT_CODE ON) link_secp256k1_internal(secp256k1_jni) endif() # Tests if(SECP256K1_BUILD_TEST) include(TestSuite) create_test_suite(secp256k1) function(create_secp256k1_test NAME FILES) add_test_to_suite(secp256k1 ${NAME} EXCLUDE_FROM_ALL ${FILES}) link_secp256k1_internal(${NAME}) endfunction() create_secp256k1_test(secp256k1-tests src/tests.c) create_secp256k1_test(secp256k1-exhaustive_tests src/tests_exhaustive.c) # This should not be enabled at the same time as coverage is. # The VERIFY failure branch is not expected to be reached, so it would make # coverage appear lower if set. if(NOT SECP256K1_ENABLE_COVERAGE) target_compile_definitions(secp256k1-tests PRIVATE VERIFY) target_compile_definitions(secp256k1-exhaustive_tests PRIVATE VERIFY) endif() if(SECP256K1_ENABLE_JNI) set(SECP256k1_JNI_TEST_JAR "secp256k1-jni-test") set(CMAKE_JNI_TARGET TRUE) add_jar(secp256k1-jni-test-jar SOURCES src/java/org/bitcoin/NativeSecp256k1.java src/java/org/bitcoin/NativeSecp256k1Test.java src/java/org/bitcoin/NativeSecp256k1Util.java src/java/org/bitcoin/Secp256k1Context.java ENTRY_POINT org/bitcoin/NativeSecp256k1Test OUTPUT_NAME "${SECP256k1_JNI_TEST_JAR}" ) add_dependencies(secp256k1-jni-test-jar secp256k1_jni) add_custom_target(check-secp256k1-java COMMAND "${Java_JAVA_EXECUTABLE}" "-Djava.library.path=${CMAKE_CURRENT_BINARY_DIR}" "-jar" "${SECP256k1_JNI_TEST_JAR}.jar" WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" ) add_dependencies(check-secp256k1-java secp256k1-jni-test-jar) add_dependencies(check-secp256k1 check-secp256k1-java) endif() endif(SECP256K1_BUILD_TEST) # Benchmarks add_secp256k1_bench(verify src/bench_verify.c) add_secp256k1_bench(sign src/bench_sign.c) add_secp256k1_bench(internal src/bench_internal.c) add_secp256k1_bench(ecmult src/bench_ecmult.c) diff --git a/src/secp256k1/src/modules/schnorr/schnorr_impl.h b/src/secp256k1/src/modules/schnorr/schnorr_impl.h index b25d3521b..9918c0bcd 100644 --- a/src/secp256k1/src/modules/schnorr/schnorr_impl.h +++ b/src/secp256k1/src/modules/schnorr/schnorr_impl.h @@ -1,220 +1,220 @@ /*********************************************************************** * Copyright (c) 2017 Amaury SÉCHET * * Distributed under the MIT software license, see the accompanying * * file COPYING or http://www.opensource.org/licenses/mit-license.php. * ***********************************************************************/ #ifndef _SECP256K1_SCHNORR_IMPL_H_ #define _SECP256K1_SCHNORR_IMPL_H_ #include #include "schnorr.h" #include "field.h" #include "group.h" #include "hash.h" #include "ecmult.h" #include "ecmult_gen.h" /** * Custom Schnorr-based signature scheme. * * Signing: * Inputs: * 32-byte message m, * 32-byte scalar key x (!=0) * public key point P, * 32-byte scalar nonce k (!=0) * * Compute point R = k * G. Negate nonce if R.y is not a quadratic residue. * Compute scalar e = Hash(R.x || compressed(P) || m) mod n. * Compute scalar s = k + e * x. * The signature is (R.x, s). * * Verification: * Inputs: * 32-byte message m, * public key point P, * signature: (32-byte r, scalar s) * * Signature is invalid if s >= n or r >= p. * Compute scalar e = Hash(r || compressed(P) || m) mod n. * Option 1 (faster for single verification): * Compute point R = s * G - e * P. * Reject if R is infinity or R.y is not a quadratic residue. * Signature is valid if the serialization of R.x equals r. * Option 2 (allows batch validation): * Decompress x coordinate r into point R, with R.y a quadratic residue. * Reject if R is not on the curve. * Signature is valid if R + e * P - s * G == 0. */ static int secp256k1_schnorr_sig_verify( const secp256k1_ecmult_context* ctx, const unsigned char *sig64, secp256k1_ge *pubkey, const unsigned char *msg32 ) { secp256k1_gej Pj, Rj; secp256k1_fe Rx; secp256k1_scalar e, s; int overflow; VERIFY_CHECK(!secp256k1_ge_is_infinity(pubkey)); /* Extract s */ overflow = 0; secp256k1_scalar_set_b32(&s, sig64 + 32, &overflow); if (overflow) { return 0; } /* Extract R.x */ if (!secp256k1_fe_set_b32(&Rx, sig64)) { return 0; } /* Compute e */ secp256k1_schnorr_compute_e(&e, sig64, pubkey, msg32); /* Verify the signature */ secp256k1_scalar_negate(&e, &e); secp256k1_gej_set_ge(&Pj, pubkey); secp256k1_ecmult(ctx, &Rj, &Pj, &e, &s); if (secp256k1_gej_is_infinity(&Rj)) { return 0; } /* Check that R.x is what we expect */ if (!secp256k1_gej_eq_x_var(&Rx, &Rj)) { return 0; } /* Check that jacobi(R.y) is 1 */ if (!secp256k1_gej_has_quad_y_var(&Rj)) { return 0; } /* All good, we have a valid signature. */ return 1; } static int secp256k1_schnorr_compute_e( secp256k1_scalar* e, const unsigned char *r, secp256k1_ge *p, const unsigned char *msg32 ) { int overflow = 0; - size_t size; + size_t size = 0; secp256k1_sha256 sha; unsigned char buf[33]; secp256k1_sha256_initialize(&sha); /* R.x */ secp256k1_sha256_write(&sha, r, 32); /* compressed P */ secp256k1_eckey_pubkey_serialize(p, buf, &size, 1); VERIFY_CHECK(size == 33); secp256k1_sha256_write(&sha, buf, 33); /* msg */ secp256k1_sha256_write(&sha, msg32, 32); /* compute e */ secp256k1_sha256_finalize(&sha, buf); secp256k1_scalar_set_b32(e, buf, &overflow); return !overflow & !secp256k1_scalar_is_zero(e); } static int secp256k1_schnorr_sig_sign( const secp256k1_context* ctx, unsigned char *sig64, const unsigned char *msg32, const secp256k1_scalar *privkey, secp256k1_ge *pubkey, secp256k1_nonce_function noncefp, const void *ndata ) { secp256k1_ge R; secp256k1_gej Rj; secp256k1_scalar k, e, s; ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); VERIFY_CHECK(!secp256k1_scalar_is_zero(privkey)); VERIFY_CHECK(!secp256k1_ge_is_infinity(pubkey)); if (!secp256k1_schnorr_sig_generate_k(ctx, &k, msg32, privkey, noncefp, ndata)) { return 0; } /* Compute R */ secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &Rj, &k); secp256k1_ge_set_gej(&R, &Rj); /* * We declassify R to allow using it as a branch point. * This is fine because R is not a secret. */ secp256k1_declassify(ctx, &R, sizeof(R)); /** Negate the nonce if R.y is not a quadratic residue. */ secp256k1_scalar_cond_negate(&k, !secp256k1_fe_is_quad_var(&R.y)); /* Compute the signature. */ secp256k1_fe_normalize(&R.x); secp256k1_fe_get_b32(sig64, &R.x); secp256k1_schnorr_compute_e(&e, sig64, pubkey, msg32); secp256k1_scalar_mul(&s, &e, privkey); secp256k1_scalar_add(&s, &s, &k); secp256k1_scalar_get_b32(sig64 + 32, &s); /* Cleanup locals that may contain private data. */ secp256k1_scalar_clear(&k); return 1; } static int secp256k1_schnorr_sig_generate_k( const secp256k1_context* ctx, secp256k1_scalar *k, const unsigned char *msg32, const secp256k1_scalar *privkey, secp256k1_nonce_function noncefp, const void *ndata ) { int ret = 0; unsigned int count = 0; unsigned char nonce32[32], seckey[32]; /* Seed used to make sure we generate different values of k for schnorr */ const unsigned char secp256k1_schnorr_algo16[17] = "Schnorr+SHA256 "; if (noncefp == NULL) { noncefp = secp256k1_nonce_function_default; } secp256k1_scalar_get_b32(seckey, privkey); while (1) { int overflow; ret = noncefp(nonce32, msg32, seckey, secp256k1_schnorr_algo16, (void*)ndata, count++); if (!ret) { break; } secp256k1_scalar_set_b32(k, nonce32, &overflow); overflow |= secp256k1_scalar_is_zero(k); /* The nonce is still secret here, but it overflowing or being zero is is less likely than 1:2^255. */ secp256k1_declassify(ctx, &overflow, sizeof(overflow)); if (!overflow) { break; } secp256k1_scalar_clear(k); } /* Cleanup locals that may contain private data. */ memset(seckey, 0, 32); memset(nonce32, 0, 32); return ret; } #endif