diff --git a/src/secp256k1/.travis.yml b/src/secp256k1/.travis.yml index e01ffd57ce..e6bed7030d 100644 --- a/src/secp256k1/.travis.yml +++ b/src/secp256k1/.travis.yml @@ -1,103 +1,106 @@ language: c os: linux dist: xenial addons: apt: sources: - sourceline: 'deb https://apt.kitware.com/ubuntu/ xenial main' key_url: 'https://apt.kitware.com/keys/kitware-archive-latest.asc' packages: - cmake - libgmp-dev - ninja-build compiler: - clang - gcc env: global: - FIELD=auto - BIGNUM=auto - SCALAR=auto - ENDOMORPHISM=no - STATICPRECOMPUTATION=yes + - ECMULTGENPRECISION=auto - ASM=no - AUTOTOOLS_TARGET=check - CMAKE_TARGET=check-secp256k1 - AUTOTOOLS_EXTRA_FLAGS= - CMAKE_EXTRA_FLAGS= - HOST= - ECDH=no - RECOVERY=no - SCHNORR=yes - EXPERIMENTAL=no - JNI=no jobs: - SCALAR=32bit RECOVERY=yes - SCALAR=32bit FIELD=32bit ECDH=yes EXPERIMENTAL=yes - SCALAR=64bit - FIELD=64bit RECOVERY=yes - FIELD=64bit ENDOMORPHISM=yes - FIELD=64bit ENDOMORPHISM=yes ECDH=yes EXPERIMENTAL=yes - FIELD=64bit ASM=x86_64 - FIELD=64bit ENDOMORPHISM=yes ASM=x86_64 - FIELD=32bit ENDOMORPHISM=yes - BIGNUM=no - BIGNUM=no ENDOMORPHISM=yes RECOVERY=yes EXPERIMENTAL=yes - BIGNUM=no STATICPRECOMPUTATION=no - AUTOTOOLS_TARGET=distcheck CMAKE_TARGET=install - AUTOTOOLS_EXTRA_FLAGS=CPPFLAGS=-DDETERMINISTIC CMAKE_EXTRA_FLAGS=-DCMAKE_C_FLAGS=-DDETERMINISTIC - AUTOTOOLS_EXTRA_FLAGS=CFLAGS=-O0 CMAKE_EXTRA_FLAGS=-DCMAKE_BUILD_TYPE=Debug - AUTOTOOLS_TARGET=check-java CMAKE_TARGET=check-secp256k1-java JNI=yes ECDH=yes EXPERIMENTAL=yes + - ECMULTGENPRECISION=2 + - ECMULTGENPRECISION=8 - SCHNORR=no jobs: fast_finish: true include: - compiler: clang env: HOST=i686-linux-gnu ENDOMORPHISM=yes addons: apt: sources: - sourceline: 'deb https://apt.kitware.com/ubuntu/ xenial main' key_url: 'https://apt.kitware.com/keys/kitware-archive-latest.asc' packages: - cmake - gcc-multilib - libgmp-dev:i386 - ninja-build - compiler: clang env: HOST=i686-linux-gnu BIGNUM=no addons: apt: sources: - sourceline: 'deb https://apt.kitware.com/ubuntu/ xenial main' key_url: 'https://apt.kitware.com/keys/kitware-archive-latest.asc' packages: - cmake - gcc-multilib - ninja-build - compiler: gcc env: HOST=i686-linux-gnu ENDOMORPHISM=yes BIGNUM=no addons: apt: sources: - sourceline: 'deb https://apt.kitware.com/ubuntu/ xenial main' key_url: 'https://apt.kitware.com/keys/kitware-archive-latest.asc' packages: - cmake - gcc-multilib - ninja-build - compiler: gcc env: HOST=i686-linux-gnu addons: apt: sources: - sourceline: 'deb https://apt.kitware.com/ubuntu/ xenial main' key_url: 'https://apt.kitware.com/keys/kitware-archive-latest.asc' packages: - cmake - gcc-multilib - libgmp-dev:i386 - ninja-build script: - ./travis/build_autotools.sh - ./travis/build_cmake.sh diff --git a/src/secp256k1/CMakeLists.txt b/src/secp256k1/CMakeLists.txt index 34d0d5e77e..01d7d7db1e 100644 --- a/src/secp256k1/CMakeLists.txt +++ b/src/secp256k1/CMakeLists.txt @@ -1,331 +1,338 @@ # Copyright (c) 2017 The Bitcoin developers cmake_minimum_required(VERSION 3.13) 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) endif() # TODO: use -O0 instead of -O3 when coverage is enabled set(CMAKE_C_FLAGS_RELWITHDEBINFO "-g -O3") include(AddCompilerFlags) # libsecp256k1 use a different set of flags. add_c_compiler_flags( -pedantic -Wall -Wextra -Wcast-align -Wshadow -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_include_directories(secp256k1 PUBLIC ${GMP_INCLUDE_DIR}) target_link_libraries(secp256k1 ${GMP_LIBRARY}) 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() # We check if amd64 asm is supported. option(SECP256K1_USE_ASM "Use assembly if available" ON) if($SECP256K1_USE_ASM) 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) else() set(USE_ASM_X86_64 0) endif() # We make sure __int128 is defined include(CheckTypeSize) check_type_size(__int128 SIZEOF___INT128) if(SIZEOF___INT128 EQUAL 16) set(HAVE___INT128 1) else() # If we do not support __int128, we should be falling back # on 32bits implementations for field and scalar. endif() # Select the finite field implementation to use. # This can be autodetected or forced by setting USE_FIELD to 32bit or 64bit. # See the truth table below: # +----------------------------------------------------------------------------------------------------------------------+ # | USE_FIELD=64bit | USE_FIELD=32bit | HAVE___INT128 | USE_ASM_X86_64 | USE_FIELD_5X52 | USE_FIELD_10x26 | Config error | # +----------------------------------------------------------------------------------------------------------------------+ # | 0 | 0 | 0 | 0 | 0 | 1 | 0 | # | 0 | 0 | 0 | 1 | 1 | 0 | 0 | # | 0 | 0 | 1 | 0 | 1 | 0 | 0 | # | 0 | 0 | 1 | 1 | 1 | 0 | 0 | # | 0 | 1 | 0 | 0 | 0 | 1 | 0 | # | 0 | 1 | 0 | 1 | 0 | 1 | 0 | # | 0 | 1 | 1 | 0 | 0 | 1 | 0 | # | 0 | 1 | 1 | 1 | 0 | 1 | 0 | # | 1 | 0 | 0 | 0 | 0 | 0 | 1 | # | 1 | 0 | 0 | 1 | 1 | 0 | 0 | # | 1 | 0 | 1 | 0 | 1 | 0 | 0 | # | 1 | 0 | 1 | 1 | 1 | 0 | 0 | # +----------------------------------------------------------------------------------------------------------------------+ set(USE_FIELD "" CACHE STRING "Force the finite field implementation to use (can be 32bit or 64bit)") if(USE_FIELD STREQUAL "64bit" AND NOT (HAVE___INT128 OR USE_ASM_X86_64)) message(SEND_ERROR "64 finite field requested but the compiler does not support __int128 or inline assembly") elseif(NOT USE_FIELD STREQUAL "32bit" AND (HAVE___INT128 OR USE_ASM_X86_64)) set(USE_FIELD_5X52 1) else() set(USE_FIELD_10X26 1) endif() # Select the scalar implementation to use. # This can be autodetected or forced by setting USE_SCALAR to 32bit or 64bit. # See the truth table below: # +--------------------------------------------------------------------------------------------------------+ # | USE_SCALAR=64bit | USE_SCALAR=32bit | HAVE___INT128 | USE_SCALAR_4X64 | USE_SCALAR_8X32 | Config error | # +--------------------------------------------------------------------------------------------------------+ # | 0 | 0 | 0 | 0 | 1 | 0 | # | 0 | 0 | 1 | 1 | 0 | 0 | # | 0 | 1 | 0 | 0 | 1 | 0 | # | 0 | 1 | 1 | 0 | 1 | 0 | # | 1 | 0 | 0 | 0 | 0 | 1 | # | 1 | 0 | 1 | 1 | 0 | 0 | # +--------------------------------------------------------------------------------------------------------+ set(USE_SCALAR "" CACHE STRING "Force the scalar implementation to use (can be 32bit or 64bit)") if(USE_SCALAR STREQUAL "64bit" AND NOT HAVE___INT128) message(SEND_ERROR "64 scalar requested but the compiler does not support __int128") elseif(NOT USE_SCALAR STREQUAL "32bit" AND HAVE___INT128) set(USE_SCALAR_4X64 1) else() set(USE_SCALAR_8X32 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) endfunction(link_secp256k1_internal) # 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}) 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" ON) 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() # 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) 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) - 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() include(NativeExecutable) native_add_cmake_flags( "-DSECP256K1_ECMULT_WINDOW_SIZE=${SECP256K1_ECMULT_WINDOW_SIZE}" + "-DSECP256K1_ECMULT_GEN_PRECISION=${SECP256K1_ECMULT_GEN_PRECISION}" ) 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() include(InstallationHelper) if(BUILD_SHARED_LIBS) install_shared_library(secp256k1 PUBLIC_HEADER ${SECP256K1_PUBLIC_HEADERS}) else() set_property(TARGET secp256k1 PROPERTY PUBLIC_HEADER ${SECP256K1_PUBLIC_HEADERS}) install_target(secp256k1) 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) 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 option(SECP256K1_BUILD_TEST "Build secp256k1's unit tests" ON) 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(tests src/tests.c) target_compile_definitions(tests PRIVATE VERIFY) create_secp256k1_test(exhaustive_tests src/tests_exhaustive.c) # This should not be enabled at the same time as coverage is. # TODO: support coverage. target_compile_definitions(exhaustive_tests PRIVATE VERIFY) 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/Makefile.am b/src/secp256k1/Makefile.am index 885afccbb8..b51968e34c 100644 --- a/src/secp256k1/Makefile.am +++ b/src/secp256k1/Makefile.am @@ -1,186 +1,186 @@ ACLOCAL_AMFLAGS = -I build-aux/m4 SECP256K1_LIB = libsecp256k1.la lib_LTLIBRARIES = $(SECP256K1_LIB) if USE_JNI lib_LTLIBRARIES += libsecp256k1_jni.la endif include_HEADERS = include/secp256k1.h include_HEADERS += include/secp256k1_preallocated.h noinst_HEADERS = noinst_HEADERS += src/scalar.h noinst_HEADERS += src/scalar_4x64.h noinst_HEADERS += src/scalar_8x32.h noinst_HEADERS += src/scalar_low.h noinst_HEADERS += src/scalar_impl.h noinst_HEADERS += src/scalar_4x64_impl.h noinst_HEADERS += src/scalar_8x32_impl.h noinst_HEADERS += src/scalar_low_impl.h noinst_HEADERS += src/group.h noinst_HEADERS += src/group_impl.h noinst_HEADERS += src/num_gmp.h noinst_HEADERS += src/num_gmp_impl.h noinst_HEADERS += src/ecdsa.h noinst_HEADERS += src/ecdsa_impl.h noinst_HEADERS += src/eckey.h noinst_HEADERS += src/eckey_impl.h noinst_HEADERS += src/ecmult.h noinst_HEADERS += src/ecmult_impl.h noinst_HEADERS += src/ecmult_const.h noinst_HEADERS += src/ecmult_const_impl.h noinst_HEADERS += src/ecmult_gen.h noinst_HEADERS += src/ecmult_gen_impl.h noinst_HEADERS += src/num.h noinst_HEADERS += src/num_impl.h noinst_HEADERS += src/field_10x26.h noinst_HEADERS += src/field_10x26_impl.h noinst_HEADERS += src/field_5x52.h noinst_HEADERS += src/field_5x52_impl.h noinst_HEADERS += src/field_5x52_int128_impl.h noinst_HEADERS += src/field_5x52_asm_impl.h noinst_HEADERS += src/java/org_bitcoin_NativeSecp256k1.h noinst_HEADERS += src/java/org_bitcoin_Secp256k1Context.h noinst_HEADERS += src/util.h noinst_HEADERS += src/scratch.h noinst_HEADERS += src/scratch_impl.h noinst_HEADERS += src/testrand.h noinst_HEADERS += src/testrand_impl.h noinst_HEADERS += src/hash.h noinst_HEADERS += src/hash_impl.h noinst_HEADERS += src/field.h noinst_HEADERS += src/field_impl.h noinst_HEADERS += src/bench.h noinst_HEADERS += contrib/lax_der_parsing.h noinst_HEADERS += contrib/lax_der_parsing.c noinst_HEADERS += contrib/lax_der_privatekey_parsing.h noinst_HEADERS += contrib/lax_der_privatekey_parsing.c if USE_EXTERNAL_ASM COMMON_LIB = libsecp256k1_common.la noinst_LTLIBRARIES = $(COMMON_LIB) else COMMON_LIB = endif pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = libsecp256k1.pc if USE_EXTERNAL_ASM if USE_ASM_ARM libsecp256k1_common_la_SOURCES = src/asm/field_10x26_arm.s endif endif libsecp256k1_la_SOURCES = src/secp256k1.c libsecp256k1_la_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/include -I$(top_srcdir)/src $(SECP_INCLUDES) libsecp256k1_la_LIBADD = $(SECP_LIBS) $(COMMON_LIB) libsecp256k1_jni_la_SOURCES = src/java/org_bitcoin_NativeSecp256k1.c src/java/org_bitcoin_Secp256k1Context.c libsecp256k1_jni_la_CPPFLAGS = -DSECP256K1_BUILD $(JNI_INCLUDES) libsecp256k1_jni_la_LIBADD = $(SECP256K1_LIB) noinst_PROGRAMS = if USE_BENCHMARK noinst_PROGRAMS += bench_verify bench_sign bench_internal bench_ecmult bench_verify_SOURCES = src/bench_verify.c bench_verify_LDADD = libsecp256k1.la $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB) bench_sign_SOURCES = src/bench_sign.c bench_sign_LDADD = libsecp256k1.la $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB) bench_internal_SOURCES = src/bench_internal.c bench_internal_LDADD = $(SECP_LIBS) $(COMMON_LIB) bench_internal_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/src $(SECP_INCLUDES) bench_ecmult_SOURCES = src/bench_ecmult.c bench_ecmult_LDADD = $(SECP_LIBS) $(COMMON_LIB) bench_ecmult_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/src $(SECP_INCLUDES) endif TESTS = if USE_TESTS noinst_PROGRAMS += tests tests_SOURCES = src/tests.c tests_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/src -I$(top_srcdir)/include $(SECP_INCLUDES) $(SECP_TEST_INCLUDES) if !ENABLE_COVERAGE tests_CPPFLAGS += -DVERIFY endif tests_LDADD = $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB) tests_LDFLAGS = -static TESTS += tests endif if USE_EXHAUSTIVE_TESTS noinst_PROGRAMS += exhaustive_tests exhaustive_tests_SOURCES = src/tests_exhaustive.c exhaustive_tests_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/src $(SECP_INCLUDES) if !ENABLE_COVERAGE exhaustive_tests_CPPFLAGS += -DVERIFY endif exhaustive_tests_LDADD = $(SECP_LIBS) $(COMMON_LIB) exhaustive_tests_LDFLAGS = -static TESTS += exhaustive_tests endif JAVA_ROOT=src/java JAVA_ORG=org/bitcoin JAVA_SRC=$(top_srcdir)/$(JAVA_ROOT)/$(JAVA_ORG) JAVA_BUILD=$(top_builddir)/$(JAVA_ROOT) JAVA_FILES= \ $(JAVA_SRC)/NativeSecp256k1.java \ $(JAVA_SRC)/NativeSecp256k1Test.java \ $(JAVA_SRC)/NativeSecp256k1Util.java \ $(JAVA_SRC)/Secp256k1Context.java if USE_JNI .stamp-java: $(JAVA_FILES) @echo Compiling $^ $(AM_V_at)javac -d "$(JAVA_BUILD)" $^ @touch $@ if USE_TESTS check-java: libsecp256k1_jni.la .stamp-java $(AM_V_at)java -Djava.library.path="./:./src:./src/.libs:.libs/" -enableassertions -cp "$(JAVA_BUILD)" $(JAVA_ORG)/NativeSecp256k1Test endif endif if USE_ECMULT_STATIC_PRECOMPUTATION -CPPFLAGS_FOR_BUILD +=-I$(top_srcdir) +CPPFLAGS_FOR_BUILD +=-I$(top_srcdir) -I$(builddir)/src gen_context_OBJECTS = gen_context.o gen_context_BIN = gen_context$(BUILD_EXEEXT) -gen_%.o: src/gen_%.c +gen_%.o: src/gen_%.c src/libsecp256k1-config.h $(CC_FOR_BUILD) $(CPPFLAGS_FOR_BUILD) $(CFLAGS_FOR_BUILD) -c $< -o $@ $(gen_context_BIN): $(gen_context_OBJECTS) $(CC_FOR_BUILD) $(CFLAGS_FOR_BUILD) $(LDFLAGS_FOR_BUILD) $^ -o $@ $(libsecp256k1_la_OBJECTS): src/ecmult_static_context.h $(tests_OBJECTS): src/ecmult_static_context.h $(bench_internal_OBJECTS): src/ecmult_static_context.h $(bench_ecmult_OBJECTS): src/ecmult_static_context.h src/ecmult_static_context.h: $(gen_context_BIN) ./$(gen_context_BIN) CLEANFILES = $(gen_context_BIN) src/ecmult_static_context.h $(JAVA_BUILD)/$(JAVA_ORG)/*.class .stamp-java endif EXTRA_DIST = autogen.sh src/gen_context.c src/basic-config.h $(JAVA_FILES) if ENABLE_MODULE_ECDH include src/modules/ecdh/Makefile.am.include endif if ENABLE_MODULE_MULTISET include src/modules/multiset/Makefile.am.include endif if ENABLE_MODULE_RECOVERY include src/modules/recovery/Makefile.am.include endif if ENABLE_MODULE_SCHNORR include src/modules/schnorr/Makefile.am.include endif diff --git a/src/secp256k1/README.md b/src/secp256k1/README.md index d3d9d23d36..32e5efd217 100644 --- a/src/secp256k1/README.md +++ b/src/secp256k1/README.md @@ -1,80 +1,89 @@ libsecp256k1 ============ [![Build Status](https://travis-ci.org/bitcoin-abc/secp256k1.svg?branch=master)](https://travis-ci.org/bitcoin-abc/secp256k1) Optimized C library for cryptographic operations on curve secp256k1. This library is used for consensus critical cryptographic operations on the Bitcoin Cash network. It is maintained within the Bitcoin ABC repository, and is mirrored as a separate repository for ease of reuse in other Bitcoin Cash projects. Developers who want to contribute may do so at [reviews.bitcoinabc.org](https://reviews.bitcoinabc.org/). Use at your own risk. Features: * secp256k1 ECDSA signing/verification and key generation. * secp256k1 Schnorr signing/verification ([Bitcoin Cash Schnorr variant](https://www.bitcoincash.org/spec/2019-05-15-schnorr.html)). * Adding/multiplying private/public keys. * Serialization/parsing of private keys, public keys, signatures. * Constant time, constant memory access signing and pubkey generation. * Derandomized DSA (via RFC6979 or with a caller provided function.) * Very efficient implementation. Implementation details ---------------------- * General * No runtime heap allocation. * Extensive testing infrastructure. * Structured to facilitate review and analysis. * Intended to be portable to any system with a C89 compiler and uint64_t support. * No use of floating types, except in benchmarks. * Expose only higher level interfaces to minimize the API surface and improve application security. ("Be difficult to use insecurely.") * Field operations * Optimized implementation of arithmetic modulo the curve's field size (2^256 - 0x1000003D1). * Using 5 52-bit limbs (including hand-optimized assembly for x86_64, by Diederik Huys). * Using 10 26-bit limbs. * Field inverses and square roots using a sliding window over blocks of 1s (by Peter Dettman). * Scalar operations * Optimized implementation without data-dependent branches of arithmetic modulo the curve's order. * Using 4 64-bit limbs (relying on __int128 support in the compiler). * Using 8 32-bit limbs. * Group operations * Point addition formula specifically simplified for the curve equation (y^2 = x^3 + 7). * Use addition between points in Jacobian and affine coordinates where possible. * Use a unified addition/doubling formula where necessary to avoid data-dependent branches. * Point/x comparison without a field inversion by comparison in the Jacobian coordinate space. * Point multiplication for verification (a*P + b*G). * Use wNAF notation for point multiplicands. * Use a much larger window for multiples of G, using precomputed multiples. * Use Shamir's trick to do the multiplication with the public key and the generator simultaneously. * Optionally (off by default) use secp256k1's efficiently-computable endomorphism to split the P multiplicand into 2 half-sized ones. * Point multiplication for signing * Use a precomputed table of multiples of powers of 16 multiplied with the generator, so general multiplication becomes a series of additions. * Intended to be completely free of timing sidechannels for secret-key operations (on reasonable hardware/toolchains) * Access the table with branch-free conditional moves so memory access is uniform. * No data-dependent branches * Optional runtime blinding which attempts to frustrate differential power analysis. * The precomputed tables add and eventually subtract points for which no known scalar (private key) is known, preventing even an attacker with control over the private key used to control the data internally. Build steps ----------- libsecp256k1 can be built using autotools: ```bash ./autogen.sh mkdir build cd build ../configure make make check sudo make install # optional ``` Or using CMake: ```bash mkdir build cd build cmake -GNinja .. ninja ninja check-secp256k1 sudo ninja install # optional ``` + +Exhaustive tests +----------- + + $ ./exhaustive_tests + +With valgrind, you might need to increase the max stack size: + + $ valgrind --max-stackframe=2500000 ./exhaustive_tests diff --git a/src/secp256k1/configure.ac b/src/secp256k1/configure.ac index 4b6f9c3fe0..b31a498a05 100644 --- a/src/secp256k1/configure.ac +++ b/src/secp256k1/configure.ac @@ -1,588 +1,613 @@ AC_PREREQ([2.60]) AC_INIT([libsecp256k1],[0.1]) AC_CONFIG_AUX_DIR([build-aux]) AC_CONFIG_MACRO_DIR([build-aux/m4]) AC_CANONICAL_HOST AH_TOP([#ifndef LIBSECP256K1_CONFIG_H]) AH_TOP([#define LIBSECP256K1_CONFIG_H]) AH_BOTTOM([#endif /*LIBSECP256K1_CONFIG_H*/]) AM_INIT_AUTOMAKE([foreign subdir-objects]) LT_INIT dnl make the compilation flags quiet unless V=1 is used m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) PKG_PROG_PKG_CONFIG AC_PATH_TOOL(AR, ar) AC_PATH_TOOL(RANLIB, ranlib) AC_PATH_TOOL(STRIP, strip) AX_PROG_CC_FOR_BUILD if test "x$CFLAGS" = "x"; then CFLAGS="-g" fi AM_PROG_CC_C_O AC_PROG_CC_C89 if test x"$ac_cv_prog_cc_c89" = x"no"; then AC_MSG_ERROR([c89 compiler support required]) fi AM_PROG_AS case $host_os in *darwin*) if test x$cross_compiling != xyes; then AC_PATH_PROG([BREW],brew,) if test x$BREW != x; then dnl These Homebrew packages may be keg-only, meaning that they won't be found dnl in expected paths because they may conflict with system files. Ask dnl Homebrew where each one is located, then adjust paths accordingly. openssl_prefix=`$BREW --prefix openssl 2>/dev/null` gmp_prefix=`$BREW --prefix gmp 2>/dev/null` if test x$openssl_prefix != x; then PKG_CONFIG_PATH="$openssl_prefix/lib/pkgconfig:$PKG_CONFIG_PATH" export PKG_CONFIG_PATH fi if test x$gmp_prefix != x; then GMP_CPPFLAGS="-I$gmp_prefix/include" GMP_LIBS="-L$gmp_prefix/lib" fi else AC_PATH_PROG([PORT],port,) dnl if homebrew isn't installed and macports is, add the macports default paths dnl as a last resort. if test x$PORT != x; then CPPFLAGS="$CPPFLAGS -isystem /opt/local/include" LDFLAGS="$LDFLAGS -L/opt/local/lib" fi fi fi ;; esac CFLAGS="$CFLAGS -W" warn_CFLAGS="-std=c89 -pedantic -Wall -Wextra -Wcast-align -Wnested-externs -Wshadow -Wstrict-prototypes -Wno-unused-function -Wno-long-long -Wno-overlength-strings" saved_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $warn_CFLAGS" AC_MSG_CHECKING([if ${CC} supports ${warn_CFLAGS}]) AC_COMPILE_IFELSE([AC_LANG_SOURCE([[char foo;]])], [ AC_MSG_RESULT([yes]) ], [ AC_MSG_RESULT([no]) CFLAGS="$saved_CFLAGS" ]) saved_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -fvisibility=hidden" AC_MSG_CHECKING([if ${CC} supports -fvisibility=hidden]) AC_COMPILE_IFELSE([AC_LANG_SOURCE([[char foo;]])], [ AC_MSG_RESULT([yes]) ], [ AC_MSG_RESULT([no]) CFLAGS="$saved_CFLAGS" ]) AC_ARG_ENABLE(benchmark, AS_HELP_STRING([--enable-benchmark],[compile benchmark [default=yes]]), [use_benchmark=$enableval], [use_benchmark=yes]) AC_ARG_ENABLE(coverage, AS_HELP_STRING([--enable-coverage],[enable compiler flags to support kcov coverage analysis [default=no]]), [enable_coverage=$enableval], [enable_coverage=no]) AC_ARG_ENABLE(tests, AS_HELP_STRING([--enable-tests],[compile tests [default=yes]]), [use_tests=$enableval], [use_tests=yes]) AC_ARG_ENABLE(openssl_tests, AS_HELP_STRING([--enable-openssl-tests],[enable OpenSSL tests [default=auto]]), [enable_openssl_tests=$enableval], [enable_openssl_tests=auto]) AC_ARG_ENABLE(experimental, AS_HELP_STRING([--enable-experimental],[allow experimental configure options [default=no]]), [use_experimental=$enableval], [use_experimental=no]) AC_ARG_ENABLE(exhaustive_tests, AS_HELP_STRING([--enable-exhaustive-tests],[compile exhaustive tests [default=yes]]), [use_exhaustive_tests=$enableval], [use_exhaustive_tests=yes]) AC_ARG_ENABLE(endomorphism, AS_HELP_STRING([--enable-endomorphism],[enable endomorphism [default=no]]), [use_endomorphism=$enableval], [use_endomorphism=no]) AC_ARG_ENABLE(ecmult_static_precomputation, AS_HELP_STRING([--enable-ecmult-static-precomputation],[enable precomputed ecmult table for signing [default=auto]]), [use_ecmult_static_precomputation=$enableval], [use_ecmult_static_precomputation=auto]) AC_ARG_ENABLE(module_ecdh, AS_HELP_STRING([--enable-module-ecdh],[enable ECDH shared secret computation (experimental)]), [enable_module_ecdh=$enableval], [enable_module_ecdh=no]) AC_ARG_ENABLE(module_multiset, AS_HELP_STRING([--enable-module-multiset],[enable multiset operations (experimental)]), [enable_module_multiset=$enableval], [enable_module_multiset=no]) AC_ARG_ENABLE(module_recovery, AS_HELP_STRING([--enable-module-recovery],[enable ECDSA pubkey recovery module [default=no]]), [enable_module_recovery=$enableval], [enable_module_recovery=no]) AC_ARG_ENABLE(module_schnorr, AS_HELP_STRING([--enable-module-schnorr],[enable Schnorr signatures module [default=yes]]), [enable_module_schnorr=$enableval], [enable_module_schnorr=yes]) AC_ARG_ENABLE(external_default_callbacks, AS_HELP_STRING([--enable-external-default-callbacks],[enable external default callback functions [default=no]]), [use_external_default_callbacks=$enableval], [use_external_default_callbacks=no]) AC_ARG_ENABLE(jni, AS_HELP_STRING([--enable-jni],[enable libsecp256k1_jni [default=no]]), [use_jni=$enableval], [use_jni=no]) AC_ARG_WITH([field], [AS_HELP_STRING([--with-field=64bit|32bit|auto], [finite field implementation to use [default=auto]])],[req_field=$withval], [req_field=auto]) AC_ARG_WITH([bignum], [AS_HELP_STRING([--with-bignum=gmp|no|auto], [bignum implementation to use [default=auto]])],[req_bignum=$withval], [req_bignum=auto]) AC_ARG_WITH([scalar], [AS_HELP_STRING([--with-scalar=64bit|32bit|auto], [scalar implementation to use [default=auto]])],[req_scalar=$withval], [req_scalar=auto]) AC_ARG_WITH([asm], [AS_HELP_STRING([--with-asm=x86_64|arm|no|auto], [assembly optimizations to use (experimental: arm) [default=auto]])],[req_asm=$withval], [req_asm=auto]) AC_ARG_WITH([ecmult-window], [AS_HELP_STRING([--with-ecmult-window=SIZE|auto], [window size for ecmult precomputation for verification, specified as integer in range [2..24].] [Larger values result in possibly better performance at the cost of an exponentially larger precomputed table.] [The table will store 2^(SIZE-2) * 64 bytes of data but can be larger in memory due to platform-specific padding and alignment.] [If the endomorphism optimization is enabled, two tables of this size are used instead of only one.] ["auto" is a reasonable setting for desktop machines (currently 15). [default=auto]] )], [req_ecmult_window=$withval], [req_ecmult_window=auto]) +AC_ARG_WITH([ecmult-gen-precision], [AS_HELP_STRING([--with-ecmult-gen-precision=2|4|8|auto], +[Precision bits to tune the precomputed table size for signing.] +[The size of the table is 32kB for 2 bits, 64kB for 4 bits, 512kB for 8 bits of precision.] +[A larger table size usually results in possible faster signing.] +["auto" is a reasonable setting for desktop machines (currently 4). [default=auto]] +)], +[req_ecmult_gen_precision=$withval], [req_ecmult_gen_precision=auto]) + AC_CHECK_TYPES([__int128]) if test x"$enable_coverage" = x"yes"; then AC_DEFINE(COVERAGE, 1, [Define this symbol to compile out all VERIFY code]) CFLAGS="$CFLAGS -O0 --coverage" LDFLAGS="$LDFLAGS --coverage" else CFLAGS="$CFLAGS -O3" fi if test x"$use_ecmult_static_precomputation" != x"no"; then # Temporarily switch to an environment for the native compiler save_cross_compiling=$cross_compiling cross_compiling=no SAVE_CC="$CC" CC="$CC_FOR_BUILD" SAVE_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS_FOR_BUILD" SAVE_CPPFLAGS="$CPPFLAGS" CPPFLAGS="$CPPFLAGS_FOR_BUILD" SAVE_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS_FOR_BUILD" warn_CFLAGS_FOR_BUILD="-Wall -Wextra -Wno-unused-function" saved_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $warn_CFLAGS_FOR_BUILD" AC_MSG_CHECKING([if native ${CC_FOR_BUILD} supports ${warn_CFLAGS_FOR_BUILD}]) AC_COMPILE_IFELSE([AC_LANG_SOURCE([[char foo;]])], [ AC_MSG_RESULT([yes]) ], [ AC_MSG_RESULT([no]) CFLAGS="$saved_CFLAGS" ]) AC_MSG_CHECKING([for working native compiler: ${CC_FOR_BUILD}]) AC_RUN_IFELSE( [AC_LANG_PROGRAM([], [])], [working_native_cc=yes], [working_native_cc=no],[dnl]) CFLAGS_FOR_BUILD="$CFLAGS" # Restore the environment cross_compiling=$save_cross_compiling CC="$SAVE_CC" CFLAGS="$SAVE_CFLAGS" CPPFLAGS="$SAVE_CPPFLAGS" LDFLAGS="$SAVE_LDFLAGS" if test x"$working_native_cc" = x"no"; then AC_MSG_RESULT([no]) set_precomp=no m4_define([please_set_for_build], [Please set CC_FOR_BUILD, CFLAGS_FOR_BUILD, CPPFLAGS_FOR_BUILD, and/or LDFLAGS_FOR_BUILD.]) if test x"$use_ecmult_static_precomputation" = x"yes"; then AC_MSG_ERROR([native compiler ${CC_FOR_BUILD} does not produce working binaries. please_set_for_build]) else AC_MSG_WARN([Disabling statically generated ecmult table because the native compiler ${CC_FOR_BUILD} does not produce working binaries. please_set_for_build]) fi else AC_MSG_RESULT([yes]) set_precomp=yes fi else set_precomp=no fi if test x"$req_asm" = x"auto"; then SECP_64BIT_ASM_CHECK if test x"$has_64bit_asm" = x"yes"; then set_asm=x86_64 fi if test x"$set_asm" = x; then set_asm=no fi else set_asm=$req_asm case $set_asm in x86_64) SECP_64BIT_ASM_CHECK if test x"$has_64bit_asm" != x"yes"; then AC_MSG_ERROR([x86_64 assembly optimization requested but not available]) fi ;; arm) ;; no) ;; *) AC_MSG_ERROR([invalid assembly optimization selection]) ;; esac fi if test x"$req_field" = x"auto"; then if test x"set_asm" = x"x86_64"; then set_field=64bit fi if test x"$set_field" = x; then SECP_INT128_CHECK if test x"$has_int128" = x"yes"; then set_field=64bit fi fi if test x"$set_field" = x; then set_field=32bit fi else set_field=$req_field case $set_field in 64bit) if test x"$set_asm" != x"x86_64"; then SECP_INT128_CHECK if test x"$has_int128" != x"yes"; then AC_MSG_ERROR([64bit field explicitly requested but neither __int128 support or x86_64 assembly available]) fi fi ;; 32bit) ;; *) AC_MSG_ERROR([invalid field implementation selection]) ;; esac fi if test x"$req_scalar" = x"auto"; then SECP_INT128_CHECK if test x"$has_int128" = x"yes"; then set_scalar=64bit fi if test x"$set_scalar" = x; then set_scalar=32bit fi else set_scalar=$req_scalar case $set_scalar in 64bit) SECP_INT128_CHECK if test x"$has_int128" != x"yes"; then AC_MSG_ERROR([64bit scalar explicitly requested but __int128 support not available]) fi ;; 32bit) ;; *) AC_MSG_ERROR([invalid scalar implementation selected]) ;; esac fi if test x"$req_bignum" = x"auto"; then SECP_GMP_CHECK if test x"$has_gmp" = x"yes"; then set_bignum=gmp fi if test x"$set_bignum" = x; then set_bignum=no fi else set_bignum=$req_bignum case $set_bignum in gmp) SECP_GMP_CHECK if test x"$has_gmp" != x"yes"; then AC_MSG_ERROR([gmp bignum explicitly requested but libgmp not available]) fi ;; no) ;; *) AC_MSG_ERROR([invalid bignum implementation selection]) ;; esac fi # select assembly optimization use_external_asm=no case $set_asm in x86_64) AC_DEFINE(USE_ASM_X86_64, 1, [Define this symbol to enable x86_64 assembly optimizations]) ;; arm) use_external_asm=yes ;; no) ;; *) AC_MSG_ERROR([invalid assembly optimizations]) ;; esac # select field implementation case $set_field in 64bit) AC_DEFINE(USE_FIELD_5X52, 1, [Define this symbol to use the FIELD_5X52 implementation]) ;; 32bit) AC_DEFINE(USE_FIELD_10X26, 1, [Define this symbol to use the FIELD_10X26 implementation]) ;; *) AC_MSG_ERROR([invalid field implementation]) ;; esac # select bignum implementation case $set_bignum in gmp) AC_DEFINE(HAVE_LIBGMP, 1, [Define this symbol if libgmp is installed]) AC_DEFINE(USE_NUM_GMP, 1, [Define this symbol to use the gmp implementation for num]) AC_DEFINE(USE_FIELD_INV_NUM, 1, [Define this symbol to use the num-based field inverse implementation]) AC_DEFINE(USE_SCALAR_INV_NUM, 1, [Define this symbol to use the num-based scalar inverse implementation]) ;; no) AC_DEFINE(USE_NUM_NONE, 1, [Define this symbol to use no num implementation]) AC_DEFINE(USE_FIELD_INV_BUILTIN, 1, [Define this symbol to use the native field inverse implementation]) AC_DEFINE(USE_SCALAR_INV_BUILTIN, 1, [Define this symbol to use the native scalar inverse implementation]) ;; *) AC_MSG_ERROR([invalid bignum implementation]) ;; esac #select scalar implementation case $set_scalar in 64bit) AC_DEFINE(USE_SCALAR_4X64, 1, [Define this symbol to use the 4x64 scalar implementation]) ;; 32bit) AC_DEFINE(USE_SCALAR_8X32, 1, [Define this symbol to use the 8x32 scalar implementation]) ;; *) AC_MSG_ERROR([invalid scalar implementation]) ;; esac #set ecmult window size if test x"$req_ecmult_window" = x"auto"; then set_ecmult_window=15 else set_ecmult_window=$req_ecmult_window fi error_window_size=['window size for ecmult precomputation not an integer in range [2..24] or "auto"'] case $set_ecmult_window in ''|*[[!0-9]]*) # no valid integer AC_MSG_ERROR($error_window_size) ;; *) if test "$set_ecmult_window" -lt 2 -o "$set_ecmult_window" -gt 24 ; then # not in range AC_MSG_ERROR($error_window_size) fi AC_DEFINE_UNQUOTED(ECMULT_WINDOW_SIZE, $set_ecmult_window, [Set window size for ecmult precomputation]) ;; esac +#set ecmult gen precision +if test x"$req_ecmult_gen_precision" = x"auto"; then + set_ecmult_gen_precision=4 +else + set_ecmult_gen_precision=$req_ecmult_gen_precision +fi + +case $set_ecmult_gen_precision in +2|4|8) + AC_DEFINE_UNQUOTED(ECMULT_GEN_PREC_BITS, $set_ecmult_gen_precision, [Set ecmult gen precision bits]) + ;; +*) + AC_MSG_ERROR(['ecmult gen precision not 2, 4, 8 or "auto"']) + ;; +esac + if test x"$use_tests" = x"yes"; then SECP_OPENSSL_CHECK if test x"$has_openssl_ec" = x"yes"; then if test x"$enable_openssl_tests" != x"no"; then AC_DEFINE(ENABLE_OPENSSL_TESTS, 1, [Define this symbol if OpenSSL EC functions are available]) SECP_TEST_INCLUDES="$SSL_CFLAGS $CRYPTO_CFLAGS" SECP_TEST_LIBS="$CRYPTO_LIBS" case $host in *mingw*) SECP_TEST_LIBS="$SECP_TEST_LIBS -lgdi32" ;; esac fi else if test x"$enable_openssl_tests" = x"yes"; then AC_MSG_ERROR([OpenSSL tests requested but OpenSSL with EC support is not available]) fi fi else if test x"$enable_openssl_tests" = x"yes"; then AC_MSG_ERROR([OpenSSL tests requested but tests are not enabled]) fi fi if test x"$use_jni" != x"no"; then AX_JNI_INCLUDE_DIR have_jni_dependencies=yes if test x"$enable_module_ecdh" = x"no"; then have_jni_dependencies=no fi if test "x$JNI_INCLUDE_DIRS" = "x"; then have_jni_dependencies=no fi if test "x$have_jni_dependencies" = "xno"; then if test x"$use_jni" = x"yes"; then AC_MSG_ERROR([jni support explicitly requested but headers/dependencies were not found. Enable ECDH and try again.]) fi AC_MSG_WARN([jni headers/dependencies not found. jni support disabled]) use_jni=no else use_jni=yes for JNI_INCLUDE_DIR in $JNI_INCLUDE_DIRS; do JNI_INCLUDES="$JNI_INCLUDES -I$JNI_INCLUDE_DIR" done fi fi if test x"$set_bignum" = x"gmp"; then SECP_LIBS="$SECP_LIBS $GMP_LIBS" SECP_INCLUDES="$SECP_INCLUDES $GMP_CPPFLAGS" fi if test x"$use_endomorphism" = x"yes"; then AC_DEFINE(USE_ENDOMORPHISM, 1, [Define this symbol to use endomorphism optimization]) fi if test x"$set_precomp" = x"yes"; then AC_DEFINE(USE_ECMULT_STATIC_PRECOMPUTATION, 1, [Define this symbol to use a statically generated ecmult table]) fi if test x"$enable_module_ecdh" = x"yes"; then AC_DEFINE(ENABLE_MODULE_ECDH, 1, [Define this symbol to enable the ECDH module]) fi if test x"$enable_module_multiset" = x"yes"; then AC_DEFINE(ENABLE_MODULE_MULTISET, 1, [Define this symbol to enable the multiset module]) fi if test x"$enable_module_recovery" = x"yes"; then AC_DEFINE(ENABLE_MODULE_RECOVERY, 1, [Define this symbol to enable the ECDSA pubkey recovery module]) fi if test x"$enable_module_schnorr" = x"yes"; then AC_DEFINE(ENABLE_MODULE_SCHNORR, 1, [Define this symbol to enable the Schnorr signature module]) fi AC_C_BIGENDIAN() if test x"$use_external_asm" = x"yes"; then AC_DEFINE(USE_EXTERNAL_ASM, 1, [Define this symbol if an external (non-inline) assembly implementation is used]) fi if test x"$use_external_default_callbacks" = x"yes"; then AC_DEFINE(USE_EXTERNAL_DEFAULT_CALLBACKS, 1, [Define this symbol if an external implementation of the default callbacks is used]) fi if test x"$enable_experimental" = x"yes"; then AC_MSG_NOTICE([******]) AC_MSG_NOTICE([WARNING: experimental build]) AC_MSG_NOTICE([Experimental features do not have stable APIs or properties, and may not be safe for production use.]) AC_MSG_NOTICE([Building ECDH module: $enable_module_ecdh]) AC_MSG_NOTICE([******]) else if test x"$enable_module_ecdh" = x"yes"; then AC_MSG_ERROR([ECDH module is experimental. Use --enable-experimental to allow.]) fi if test x"$set_asm" = x"arm"; then AC_MSG_ERROR([ARM assembly optimization is experimental. Use --enable-experimental to allow.]) fi fi AC_CONFIG_HEADERS([src/libsecp256k1-config.h]) AC_CONFIG_FILES([Makefile libsecp256k1.pc]) AC_SUBST(JNI_INCLUDES) AC_SUBST(SECP_INCLUDES) AC_SUBST(SECP_LIBS) AC_SUBST(SECP_TEST_LIBS) AC_SUBST(SECP_TEST_INCLUDES) AM_CONDITIONAL([ENABLE_COVERAGE], [test x"$enable_coverage" = x"yes"]) AM_CONDITIONAL([USE_TESTS], [test x"$use_tests" != x"no"]) AM_CONDITIONAL([USE_EXHAUSTIVE_TESTS], [test x"$use_exhaustive_tests" != x"no"]) AM_CONDITIONAL([USE_BENCHMARK], [test x"$use_benchmark" = x"yes"]) AM_CONDITIONAL([USE_ECMULT_STATIC_PRECOMPUTATION], [test x"$set_precomp" = x"yes"]) AM_CONDITIONAL([ENABLE_MODULE_ECDH], [test x"$enable_module_ecdh" = x"yes"]) AM_CONDITIONAL([ENABLE_MODULE_MULTISET], [test x"$enable_module_multiset" = x"yes"]) AM_CONDITIONAL([ENABLE_MODULE_RECOVERY], [test x"$enable_module_recovery" = x"yes"]) AM_CONDITIONAL([ENABLE_MODULE_SCHNORR], [test x"$enable_module_schnorr" = x"yes"]) AM_CONDITIONAL([USE_JNI], [test x"$use_jni" = x"yes"]) AM_CONDITIONAL([USE_EXTERNAL_ASM], [test x"$use_external_asm" = x"yes"]) AM_CONDITIONAL([USE_ASM_ARM], [test x"$set_asm" = x"arm"]) dnl make sure nothing new is exported so that we don't break the cache PKGCONFIG_PATH_TEMP="$PKG_CONFIG_PATH" unset PKG_CONFIG_PATH PKG_CONFIG_PATH="$PKGCONFIG_PATH_TEMP" AC_OUTPUT echo echo "Build Options:" echo " with endomorphism = $use_endomorphism" echo " with ecmult precomp = $set_precomp" echo " with external callbacks = $use_external_default_callbacks" echo " with jni = $use_jni" echo " with benchmarks = $use_benchmark" echo " with coverage = $enable_coverage" echo " module ecdh = $enable_module_ecdh" echo " module recovery = $enable_module_recovery" echo " module multiset = $enable_module_multiset" echo " module schnorr = $enable_module_schnorr" echo echo " asm = $set_asm" echo " bignum = $set_bignum" echo " field = $set_field" echo " scalar = $set_scalar" echo " ecmult window size = $set_ecmult_window" +echo " ecmult gen prec. bits = $set_ecmult_gen_precision" echo echo " CC = $CC" echo " CFLAGS = $CFLAGS" echo " CPPFLAGS = $CPPFLAGS" echo " LDFLAGS = $LDFLAGS" echo diff --git a/src/secp256k1/src/basic-config.h b/src/secp256k1/src/basic-config.h index 3a3969d300..e9be39d4ca 100644 --- a/src/secp256k1/src/basic-config.h +++ b/src/secp256k1/src/basic-config.h @@ -1,37 +1,38 @@ /********************************************************************** * Copyright (c) 2013, 2014 Pieter Wuille * * Distributed under the MIT software license, see the accompanying * * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ #ifndef SECP256K1_BASIC_CONFIG_H #define SECP256K1_BASIC_CONFIG_H #ifdef USE_BASIC_CONFIG #undef USE_ASM_X86_64 #undef USE_ECMULT_STATIC_PRECOMPUTATION #undef USE_ENDOMORPHISM #undef USE_EXTERNAL_ASM #undef USE_EXTERNAL_DEFAULT_CALLBACKS #undef USE_FIELD_10X26 #undef USE_FIELD_5X52 #undef USE_FIELD_INV_BUILTIN #undef USE_FIELD_INV_NUM #undef USE_NUM_GMP #undef USE_NUM_NONE #undef USE_SCALAR_4X64 #undef USE_SCALAR_8X32 #undef USE_SCALAR_INV_BUILTIN #undef USE_SCALAR_INV_NUM +#undef ECMULT_WINDOW_SIZE #define USE_NUM_NONE 1 #define USE_FIELD_INV_BUILTIN 1 #define USE_SCALAR_INV_BUILTIN 1 #define USE_FIELD_10X26 1 #define USE_SCALAR_8X32 1 #define ECMULT_WINDOW_SIZE 15 #endif /* USE_BASIC_CONFIG */ #endif /* SECP256K1_BASIC_CONFIG_H */ diff --git a/src/secp256k1/src/ecmult_gen.h b/src/secp256k1/src/ecmult_gen.h index b136e94632..30815e5aa1 100644 --- a/src/secp256k1/src/ecmult_gen.h +++ b/src/secp256k1/src/ecmult_gen.h @@ -1,43 +1,50 @@ /********************************************************************** * Copyright (c) 2013, 2014 Pieter Wuille * * Distributed under the MIT software license, see the accompanying * * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ #ifndef SECP256K1_ECMULT_GEN_H #define SECP256K1_ECMULT_GEN_H #include "scalar.h" #include "group.h" +#if ECMULT_GEN_PREC_BITS != 2 && ECMULT_GEN_PREC_BITS != 4 && ECMULT_GEN_PREC_BITS != 8 +# error "Set ECMULT_GEN_PREC_BITS to 2, 4 or 8." +#endif +#define ECMULT_GEN_PREC_B ECMULT_GEN_PREC_BITS +#define ECMULT_GEN_PREC_G (1 << ECMULT_GEN_PREC_B) +#define ECMULT_GEN_PREC_N (256 / ECMULT_GEN_PREC_B) + typedef struct { /* For accelerating the computation of a*G: * To harden against timing attacks, use the following mechanism: - * * Break up the multiplicand into groups of 4 bits, called n_0, n_1, n_2, ..., n_63. - * * Compute sum(n_i * 16^i * G + U_i, i=0..63), where: - * * U_i = U * 2^i (for i=0..62) - * * U_i = U * (1-2^63) (for i=63) - * where U is a point with no known corresponding scalar. Note that sum(U_i, i=0..63) = 0. - * For each i, and each of the 16 possible values of n_i, (n_i * 16^i * G + U_i) is - * precomputed (call it prec(i, n_i)). The formula now becomes sum(prec(i, n_i), i=0..63). + * * Break up the multiplicand into groups of PREC_B bits, called n_0, n_1, n_2, ..., n_(PREC_N-1). + * * Compute sum(n_i * (PREC_G)^i * G + U_i, i=0 ... PREC_N-1), where: + * * U_i = U * 2^i, for i=0 ... PREC_N-2 + * * U_i = U * (1-2^(PREC_N-1)), for i=PREC_N-1 + * where U is a point with no known corresponding scalar. Note that sum(U_i, i=0 ... PREC_N-1) = 0. + * For each i, and each of the PREC_G possible values of n_i, (n_i * (PREC_G)^i * G + U_i) is + * precomputed (call it prec(i, n_i)). The formula now becomes sum(prec(i, n_i), i=0 ... PREC_N-1). * None of the resulting prec group elements have a known scalar, and neither do any of * the intermediate sums while computing a*G. */ - secp256k1_ge_storage (*prec)[64][16]; /* prec[j][i] = 16^j * i * G + U_i */ + secp256k1_ge_storage (*prec)[ECMULT_GEN_PREC_N][ECMULT_GEN_PREC_G]; /* prec[j][i] = (PREC_G)^j * i * G + U_i */ secp256k1_scalar blind; secp256k1_gej initial; } secp256k1_ecmult_gen_context; static const size_t SECP256K1_ECMULT_GEN_CONTEXT_PREALLOCATED_SIZE; static void secp256k1_ecmult_gen_context_init(secp256k1_ecmult_gen_context* ctx); static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context* ctx, void **prealloc); static void secp256k1_ecmult_gen_context_finalize_memcpy(secp256k1_ecmult_gen_context *dst, const secp256k1_ecmult_gen_context* src); static void secp256k1_ecmult_gen_context_clear(secp256k1_ecmult_gen_context* ctx); static int secp256k1_ecmult_gen_context_is_built(const secp256k1_ecmult_gen_context* ctx); /** Multiply with the generator: R = a*G */ static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context* ctx, secp256k1_gej *r, const secp256k1_scalar *a); static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const unsigned char *seed32); #endif /* SECP256K1_ECMULT_GEN_H */ diff --git a/src/secp256k1/src/ecmult_gen_impl.h b/src/secp256k1/src/ecmult_gen_impl.h index 0e2eafa71d..a1b9639393 100644 --- a/src/secp256k1/src/ecmult_gen_impl.h +++ b/src/secp256k1/src/ecmult_gen_impl.h @@ -1,211 +1,211 @@ /********************************************************************** * Copyright (c) 2013, 2014, 2015 Pieter Wuille, Gregory Maxwell * * Distributed under the MIT software license, see the accompanying * * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ #ifndef SECP256K1_ECMULT_GEN_IMPL_H #define SECP256K1_ECMULT_GEN_IMPL_H #include "util.h" #include "scalar.h" #include "group.h" #include "ecmult_gen.h" #include "hash_impl.h" #ifdef USE_ECMULT_STATIC_PRECOMPUTATION #include "ecmult_static_context.h" #endif #ifndef USE_ECMULT_STATIC_PRECOMPUTATION static const size_t SECP256K1_ECMULT_GEN_CONTEXT_PREALLOCATED_SIZE = ROUND_TO_ALIGN(sizeof(*((secp256k1_ecmult_gen_context*) NULL)->prec)); #else static const size_t SECP256K1_ECMULT_GEN_CONTEXT_PREALLOCATED_SIZE = 0; #endif static void secp256k1_ecmult_gen_context_init(secp256k1_ecmult_gen_context *ctx) { ctx->prec = NULL; } static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context *ctx, void **prealloc) { #ifndef USE_ECMULT_STATIC_PRECOMPUTATION - secp256k1_ge prec[1024]; + secp256k1_ge prec[ECMULT_GEN_PREC_N * ECMULT_GEN_PREC_G]; secp256k1_gej gj; secp256k1_gej nums_gej; int i, j; size_t const prealloc_size = SECP256K1_ECMULT_GEN_CONTEXT_PREALLOCATED_SIZE; void* const base = *prealloc; #endif if (ctx->prec != NULL) { return; } #ifndef USE_ECMULT_STATIC_PRECOMPUTATION - ctx->prec = (secp256k1_ge_storage (*)[64][16])manual_alloc(prealloc, prealloc_size, base, prealloc_size); + ctx->prec = (secp256k1_ge_storage (*)[ECMULT_GEN_PREC_N][ECMULT_GEN_PREC_G])manual_alloc(prealloc, prealloc_size, base, prealloc_size); /* get the generator */ secp256k1_gej_set_ge(&gj, &secp256k1_ge_const_g); /* Construct a group element with no known corresponding scalar (nothing up my sleeve). */ { static const unsigned char nums_b32[33] = "The scalar for this x is unknown"; secp256k1_fe nums_x; secp256k1_ge nums_ge; int r; r = secp256k1_fe_set_b32(&nums_x, nums_b32); (void)r; VERIFY_CHECK(r); r = secp256k1_ge_set_xo_var(&nums_ge, &nums_x, 0); (void)r; VERIFY_CHECK(r); secp256k1_gej_set_ge(&nums_gej, &nums_ge); /* Add G to make the bits in x uniformly distributed. */ secp256k1_gej_add_ge_var(&nums_gej, &nums_gej, &secp256k1_ge_const_g, NULL); } /* compute prec. */ { - secp256k1_gej precj[1024]; /* Jacobian versions of prec. */ + secp256k1_gej precj[ECMULT_GEN_PREC_N * ECMULT_GEN_PREC_G]; /* Jacobian versions of prec. */ secp256k1_gej gbase; secp256k1_gej numsbase; - gbase = gj; /* 16^j * G */ + gbase = gj; /* PREC_G^j * G */ numsbase = nums_gej; /* 2^j * nums. */ - for (j = 0; j < 64; j++) { - /* Set precj[j*16 .. j*16+15] to (numsbase, numsbase + gbase, ..., numsbase + 15*gbase). */ - precj[j*16] = numsbase; - for (i = 1; i < 16; i++) { - secp256k1_gej_add_var(&precj[j*16 + i], &precj[j*16 + i - 1], &gbase, NULL); + for (j = 0; j < ECMULT_GEN_PREC_N; j++) { + /* Set precj[j*PREC_G .. j*PREC_G+(PREC_G-1)] to (numsbase, numsbase + gbase, ..., numsbase + (PREC_G-1)*gbase). */ + precj[j*ECMULT_GEN_PREC_G] = numsbase; + for (i = 1; i < ECMULT_GEN_PREC_G; i++) { + secp256k1_gej_add_var(&precj[j*ECMULT_GEN_PREC_G + i], &precj[j*ECMULT_GEN_PREC_G + i - 1], &gbase, NULL); } - /* Multiply gbase by 16. */ - for (i = 0; i < 4; i++) { + /* Multiply gbase by PREC_G. */ + for (i = 0; i < ECMULT_GEN_PREC_B; i++) { secp256k1_gej_double_var(&gbase, &gbase, NULL); } /* Multiply numbase by 2. */ secp256k1_gej_double_var(&numsbase, &numsbase, NULL); - if (j == 62) { + if (j == ECMULT_GEN_PREC_N - 2) { /* In the last iteration, numsbase is (1 - 2^j) * nums instead. */ secp256k1_gej_neg(&numsbase, &numsbase); secp256k1_gej_add_var(&numsbase, &numsbase, &nums_gej, NULL); } } - secp256k1_ge_set_all_gej_var(prec, precj, 1024); + secp256k1_ge_set_all_gej_var(prec, precj, ECMULT_GEN_PREC_N * ECMULT_GEN_PREC_G); } - for (j = 0; j < 64; j++) { - for (i = 0; i < 16; i++) { - secp256k1_ge_to_storage(&(*ctx->prec)[j][i], &prec[j*16 + i]); + for (j = 0; j < ECMULT_GEN_PREC_N; j++) { + for (i = 0; i < ECMULT_GEN_PREC_G; i++) { + secp256k1_ge_to_storage(&(*ctx->prec)[j][i], &prec[j*ECMULT_GEN_PREC_G + i]); } } #else (void)prealloc; - ctx->prec = (secp256k1_ge_storage (*)[64][16])secp256k1_ecmult_static_context; + ctx->prec = (secp256k1_ge_storage (*)[ECMULT_GEN_PREC_N][ECMULT_GEN_PREC_G])secp256k1_ecmult_static_context; #endif secp256k1_ecmult_gen_blind(ctx, NULL); } static int secp256k1_ecmult_gen_context_is_built(const secp256k1_ecmult_gen_context* ctx) { return ctx->prec != NULL; } static void secp256k1_ecmult_gen_context_finalize_memcpy(secp256k1_ecmult_gen_context *dst, const secp256k1_ecmult_gen_context *src) { #ifndef USE_ECMULT_STATIC_PRECOMPUTATION if (src->prec != NULL) { /* We cast to void* first to suppress a -Wcast-align warning. */ - dst->prec = (secp256k1_ge_storage (*)[64][16])(void*)((unsigned char*)dst + ((unsigned char*)src->prec - (unsigned char*)src)); + dst->prec = (secp256k1_ge_storage (*)[ECMULT_GEN_PREC_N][ECMULT_GEN_PREC_G])(void*)((unsigned char*)dst + ((unsigned char*)src->prec - (unsigned char*)src)); } #else (void)dst, (void)src; #endif } static void secp256k1_ecmult_gen_context_clear(secp256k1_ecmult_gen_context *ctx) { secp256k1_scalar_clear(&ctx->blind); secp256k1_gej_clear(&ctx->initial); ctx->prec = NULL; } static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context *ctx, secp256k1_gej *r, const secp256k1_scalar *gn) { secp256k1_ge add; secp256k1_ge_storage adds; secp256k1_scalar gnb; int bits; int i, j; memset(&adds, 0, sizeof(adds)); *r = ctx->initial; /* Blind scalar/point multiplication by computing (n-b)G + bG instead of nG. */ secp256k1_scalar_add(&gnb, gn, &ctx->blind); add.infinity = 0; - for (j = 0; j < 64; j++) { - bits = secp256k1_scalar_get_bits(&gnb, j * 4, 4); - for (i = 0; i < 16; i++) { + for (j = 0; j < ECMULT_GEN_PREC_N; j++) { + bits = secp256k1_scalar_get_bits(&gnb, j * ECMULT_GEN_PREC_B, ECMULT_GEN_PREC_B); + for (i = 0; i < ECMULT_GEN_PREC_G; i++) { /** This uses a conditional move to avoid any secret data in array indexes. * _Any_ use of secret indexes has been demonstrated to result in timing * sidechannels, even when the cache-line access patterns are uniform. * See also: * "A word of warning", CHES 2013 Rump Session, by Daniel J. Bernstein and Peter Schwabe * (https://cryptojedi.org/peter/data/chesrump-20130822.pdf) and * "Cache Attacks and Countermeasures: the Case of AES", RSA 2006, * by Dag Arne Osvik, Adi Shamir, and Eran Tromer * (http://www.tau.ac.il/~tromer/papers/cache.pdf) */ secp256k1_ge_storage_cmov(&adds, &(*ctx->prec)[j][i], i == bits); } secp256k1_ge_from_storage(&add, &adds); secp256k1_gej_add_ge(r, r, &add); } bits = 0; secp256k1_ge_clear(&add); secp256k1_scalar_clear(&gnb); } /* Setup blinding values for secp256k1_ecmult_gen. */ static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const unsigned char *seed32) { secp256k1_scalar b; secp256k1_gej gb; secp256k1_fe s; unsigned char nonce32[32]; secp256k1_rfc6979_hmac_sha256 rng; int retry; unsigned char keydata[64] = {0}; if (seed32 == NULL) { /* When seed is NULL, reset the initial point and blinding value. */ secp256k1_gej_set_ge(&ctx->initial, &secp256k1_ge_const_g); secp256k1_gej_neg(&ctx->initial, &ctx->initial); secp256k1_scalar_set_int(&ctx->blind, 1); } /* The prior blinding value (if not reset) is chained forward by including it in the hash. */ secp256k1_scalar_get_b32(nonce32, &ctx->blind); /** Using a CSPRNG allows a failure free interface, avoids needing large amounts of random data, * and guards against weak or adversarial seeds. This is a simpler and safer interface than * asking the caller for blinding values directly and expecting them to retry on failure. */ memcpy(keydata, nonce32, 32); if (seed32 != NULL) { memcpy(keydata + 32, seed32, 32); } secp256k1_rfc6979_hmac_sha256_initialize(&rng, keydata, seed32 ? 64 : 32); memset(keydata, 0, sizeof(keydata)); /* Retry for out of range results to achieve uniformity. */ do { secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32); retry = !secp256k1_fe_set_b32(&s, nonce32); retry = retry || secp256k1_fe_is_zero(&s); } while (retry); /* This branch true is cryptographically unreachable. Requires sha256_hmac output > Fp. */ /* Randomize the projection to defend against multiplier sidechannels. */ secp256k1_gej_rescale(&ctx->initial, &s); secp256k1_fe_clear(&s); do { secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32); secp256k1_scalar_set_b32(&b, nonce32, &retry); /* A blinding value of 0 works, but would undermine the projection hardening. */ retry = retry || secp256k1_scalar_is_zero(&b); } while (retry); /* This branch true is cryptographically unreachable. Requires sha256_hmac output > order. */ secp256k1_rfc6979_hmac_sha256_finalize(&rng); memset(nonce32, 0, 32); secp256k1_ecmult_gen(ctx, &gb, &b); secp256k1_scalar_negate(&b, &b); ctx->blind = b; ctx->initial = gb; secp256k1_scalar_clear(&b); secp256k1_gej_clear(&gb); } #endif /* SECP256K1_ECMULT_GEN_IMPL_H */ diff --git a/src/secp256k1/src/gen_context.c b/src/secp256k1/src/gen_context.c index 82c605c5d4..0683830e41 100644 --- a/src/secp256k1/src/gen_context.c +++ b/src/secp256k1/src/gen_context.c @@ -1,79 +1,87 @@ /********************************************************************** * Copyright (c) 2013, 2014, 2015 Thomas Daede, Cory Fields * * Distributed under the MIT software license, see the accompanying * * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ +/* Autotools creates libsecp256k1-config.h, of which ECMULT_GEN_PREC_BITS is needed. */ +/* ifndef guard so downstream users can define their own if they do not use autotools. */ +#if !defined(ECMULT_GEN_PREC_BITS) +#include "libsecp256k1-config.h" +#endif #define USE_BASIC_CONFIG 1 - #include "basic-config.h" + #include "include/secp256k1.h" #include "util.h" #include "field_impl.h" #include "scalar_impl.h" #include "group_impl.h" #include "ecmult_gen_impl.h" static void default_error_callback_fn(const char* str, void* data) { (void)data; fprintf(stderr, "[libsecp256k1] internal consistency check failed: %s\n", str); abort(); } static const secp256k1_callback default_error_callback = { default_error_callback_fn, NULL }; int main(int argc, char **argv) { secp256k1_ecmult_gen_context ctx; void *prealloc, *base; int inner; int outer; FILE* fp; (void)argc; (void)argv; fp = fopen("src/ecmult_static_context.h","w"); if (fp == NULL) { fprintf(stderr, "Could not open src/ecmult_static_context.h for writing!\n"); return -1; } fprintf(fp, "#ifndef _SECP256K1_ECMULT_STATIC_CONTEXT_\n"); fprintf(fp, "#define _SECP256K1_ECMULT_STATIC_CONTEXT_\n"); fprintf(fp, "#include \"src/group.h\"\n"); fprintf(fp, "#define SC SECP256K1_GE_STORAGE_CONST\n"); - fprintf(fp, "static const secp256k1_ge_storage secp256k1_ecmult_static_context[64][16] = {\n"); + fprintf(fp, "#if ECMULT_GEN_PREC_N != %d || ECMULT_GEN_PREC_G != %d\n", ECMULT_GEN_PREC_N, ECMULT_GEN_PREC_G); + fprintf(fp, " #error configuration mismatch, invalid ECMULT_GEN_PREC_N, ECMULT_GEN_PREC_G. Try deleting ecmult_static_context.h before the build.\n"); + fprintf(fp, "#endif\n"); + fprintf(fp, "static const secp256k1_ge_storage secp256k1_ecmult_static_context[ECMULT_GEN_PREC_N][ECMULT_GEN_PREC_G] = {\n"); base = checked_malloc(&default_error_callback, SECP256K1_ECMULT_GEN_CONTEXT_PREALLOCATED_SIZE); prealloc = base; secp256k1_ecmult_gen_context_init(&ctx); secp256k1_ecmult_gen_context_build(&ctx, &prealloc); - for(outer = 0; outer != 64; outer++) { + for(outer = 0; outer != ECMULT_GEN_PREC_N; outer++) { fprintf(fp,"{\n"); - for(inner = 0; inner != 16; inner++) { + for(inner = 0; inner != ECMULT_GEN_PREC_G; inner++) { fprintf(fp," SC(%uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu)", SECP256K1_GE_STORAGE_CONST_GET((*ctx.prec)[outer][inner])); - if (inner != 15) { + if (inner != ECMULT_GEN_PREC_G - 1) { fprintf(fp,",\n"); } else { fprintf(fp,"\n"); } } - if (outer != 63) { + if (outer != ECMULT_GEN_PREC_N - 1) { fprintf(fp,"},\n"); } else { fprintf(fp,"}\n"); } } fprintf(fp,"};\n"); secp256k1_ecmult_gen_context_clear(&ctx); free(base); fprintf(fp, "#undef SC\n"); fprintf(fp, "#endif\n"); fclose(fp); return 0; } diff --git a/src/secp256k1/src/libsecp256k1-config.h.cmake.in b/src/secp256k1/src/libsecp256k1-config.h.cmake.in index fa9a919886..d88edec25e 100644 --- a/src/secp256k1/src/libsecp256k1-config.h.cmake.in +++ b/src/secp256k1/src/libsecp256k1-config.h.cmake.in @@ -1,35 +1,36 @@ /* Copyright (c) 2017 The Bitcoin developers */ #ifndef LIBSECP256K1_CONFIG_H #define LIBSECP256K1_CONFIG_H #cmakedefine HAVE___INT128 #cmakedefine USE_NUM_GMP #cmakedefine USE_FIELD_INV_NUM #cmakedefine USE_SCALAR_INV_NUM #cmakedefine USE_NUM_NONE #cmakedefine USE_FIELD_INV_BUILTIN #cmakedefine USE_SCALAR_INV_BUILTIN #cmakedefine USE_SCALAR_4X64 #cmakedefine USE_FIELD_5X52 #cmakedefine USE_SCALAR_8X32 #cmakedefine USE_FIELD_10X26 #cmakedefine USE_ASM_X86_64 #cmakedefine USE_ENDOMORPHISM #cmakedefine USE_EXTERNAL_DEFAULT_CALLBACKS #cmakedefine USE_ECMULT_STATIC_PRECOMPUTATION #define ECMULT_WINDOW_SIZE ${SECP256K1_ECMULT_WINDOW_SIZE} +#define ECMULT_GEN_PREC_BITS ${SECP256K1_ECMULT_GEN_PRECISION} #cmakedefine ENABLE_MODULE_ECDH #cmakedefine ENABLE_MODULE_MULTISET #cmakedefine ENABLE_MODULE_RECOVERY #cmakedefine ENABLE_MODULE_SCHNORR #endif /* LIBSECP256K1_CONFIG_H */ diff --git a/src/secp256k1/travis/build_autotools.sh b/src/secp256k1/travis/build_autotools.sh index 5d661a5d8e..f72455cb0b 100755 --- a/src/secp256k1/travis/build_autotools.sh +++ b/src/secp256k1/travis/build_autotools.sh @@ -1,37 +1,38 @@ #!/usr/bin/env bash export LC_ALL=C set -ex if [ -n "$HOST" ]; then USE_HOST="--host=$HOST" fi if [ "x$HOST" = "xi686-linux-gnu" ]; then CC="$CC -m32" fi ./autogen.sh mkdir buildautotools pushd buildautotools ../configure \ --enable-experimental=$EXPERIMENTAL \ --enable-endomorphism=$ENDOMORPHISM \ --with-field=$FIELD \ --with-bignum=$BIGNUM \ --with-asm=$ASM \ --with-scalar=$SCALAR \ --enable-ecmult-static-precomputation=$STATICPRECOMPUTATION \ + --with-ecmult-gen-precision=$ECMULTGENPRECISION \ --enable-module-ecdh=$ECDH \ --enable-module-recovery=$RECOVERY \ --enable-module-schnorr=$SCHNORR \ --enable-jni=$JNI \ $AUTOTOOLS_EXTRA_FLAGS \ $USE_HOST make -j2 $AUTOTOOLS_TARGET popd diff --git a/src/secp256k1/travis/build_cmake.sh b/src/secp256k1/travis/build_cmake.sh index f0f6dfb32d..d71955baa3 100755 --- a/src/secp256k1/travis/build_cmake.sh +++ b/src/secp256k1/travis/build_cmake.sh @@ -1,34 +1,35 @@ #!/usr/bin/env bash export LC_ALL=C set -ex if [ "x$HOST" = "xi686-linux-gnu" ]; then CMAKE_EXTRA_FLAGS="-DCMAKE_C_FLAGS=-m32" fi mkdir -p buildcmake/install pushd buildcmake # Use the cmake version installed via APT instead of the Travis custom one. CMAKE_COMMAND=/usr/bin/cmake ${CMAKE_COMMAND} --version ${CMAKE_COMMAND} -GNinja .. \ -DCMAKE_INSTALL_PREFIX=install \ -DSECP256K1_ECMULT_STATIC_PRECOMPUTATION=$STATICPRECOMPUTATION \ + -DSECP256K1_ECMULT_GEN_PRECISION=$ECMULTGENPRECISION \ -DSECP256K1_ENABLE_MODULE_ECDH=$ECDH \ -DSECP256K1_ENABLE_MODULE_RECOVERY=$RECOVERY \ -DSECP256K1_ENABLE_MODULE_SCHNORR=$SCHNORR \ -DSECP256K1_ENABLE_JNI=$JNI \ -DSECP256K1_ENABLE_ENDOMORPHISM=$ENDOMORPHISM \ -DSECP256K1_ENABLE_BIGNUM=$BIGNUM \ -DSECP256K1_USE_ASM=$ASM \ -DUSE_FIELD=$FIELD \ -DUSE_SCALAR=$SCALAR \ $CMAKE_EXTRA_FLAGS ninja $CMAKE_TARGET popd