diff --git a/.cirrus.yml b/.cirrus.yml index bbfbf71654..0b904a4e38 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -380,3 +380,30 @@ task: test_script: - cd sage - sage prove_group_implementations.sage + +task: + name: "x86_64: Windows (VS 2022)" + windows_container: + image: cirrusci/windowsservercore:visualstudio2022 + cpu: 4 + memory: 3840MB + env: + PATH: '%CIRRUS_WORKING_DIR%\build\src\RelWithDebInfo;%PATH%' + x64_NATIVE_TOOLS: '"C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Auxiliary\Build\vcvars64.bat"' + # Ignore MSBuild warning MSB8029. + # See: https://learn.microsoft.com/en-us/visualstudio/msbuild/errors/msb8029?view=vs-2022 + IgnoreWarnIntDirInTempDetected: 'true' + merge_script: + - PowerShell -NoLogo -Command if ($env:CIRRUS_PR -ne $null) { git fetch $env:CIRRUS_REPO_CLONE_URL pull/$env:CIRRUS_PR/merge; git reset --hard FETCH_HEAD; } + configure_script: + - '%x64_NATIVE_TOOLS%' + - cmake -G "Visual Studio 17 2022" -A x64 -S . -B build -DSECP256K1_ENABLE_MODULE_RECOVERY=ON -DSECP256K1_BUILD_EXAMPLES=ON + build_script: + - '%x64_NATIVE_TOOLS%' + - cmake --build build --config RelWithDebInfo -- -property:UseMultiToolTask=true;CL_MPcount=5 + check_script: + - '%x64_NATIVE_TOOLS%' + - ctest --test-dir build -j 5 + - build\src\RelWithDebInfo\bench_ecmult.exe + - build\src\RelWithDebInfo\bench_internal.exe + - build\src\RelWithDebInfo\bench.exe diff --git a/.gitignore b/.gitignore index 7c5e51b506..bc7e499de7 100644 --- a/.gitignore +++ b/.gitignore @@ -58,3 +58,6 @@ build-aux/missing build-aux/compile build-aux/test-driver libsecp256k1.pc + +# Default CMake build directory. +/build diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000000..19844da27e --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,302 @@ +cmake_minimum_required(VERSION 3.1) + +if(CMAKE_VERSION VERSION_GREATER 3.14) + # MSVC runtime library flags are selected by the CMAKE_MSVC_RUNTIME_LIBRARY abstraction. + cmake_policy(SET CMP0091 NEW) + # MSVC warning flags are not in CMAKE__FLAGS by default. + cmake_policy(SET CMP0092 NEW) +endif() + +# The package (a.k.a. release) version is based on semantic versioning 2.0.0 of +# the API. All changes in experimental modules are treated as +# backwards-compatible and therefore at most increase the minor version. +project(secp256k1 VERSION 0.2.1 LANGUAGES C) + +# The library version is based on libtool versioning of the ABI. The set of +# rules for updating the version can be found here: +# https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html +# All changes in experimental modules are treated as if they don't affect the +# interface and therefore only increase the revision. +set(${PROJECT_NAME}_LIB_VERSION_CURRENT 1) +set(${PROJECT_NAME}_LIB_VERSION_REVISION 1) +set(${PROJECT_NAME}_LIB_VERSION_AGE 0) + +set(CMAKE_C_STANDARD 90) +set(CMAKE_C_EXTENSIONS OFF) + +list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake) + +# We do not use CMake's BUILD_SHARED_LIBS option. +option(SECP256K1_BUILD_SHARED "Build shared library." ON) +option(SECP256K1_BUILD_STATIC "Build static library." ON) +if(NOT SECP256K1_BUILD_SHARED AND NOT SECP256K1_BUILD_STATIC) + message(FATAL_ERROR "At least one of SECP256K1_BUILD_SHARED and SECP256K1_BUILD_STATIC must be enabled.") +endif() + +option(SECP256K1_ENABLE_MODULE_ECDH "Enable ECDH module." ON) +if(SECP256K1_ENABLE_MODULE_ECDH) + add_definitions(-DENABLE_MODULE_ECDH=1) +endif() + +option(SECP256K1_ENABLE_MODULE_RECOVERY "Enable ECDSA pubkey recovery module." OFF) +if(SECP256K1_ENABLE_MODULE_RECOVERY) + add_definitions(-DENABLE_MODULE_RECOVERY=1) +endif() + +option(SECP256K1_ENABLE_MODULE_EXTRAKEYS "Enable extrakeys module." ON) +option(SECP256K1_ENABLE_MODULE_SCHNORRSIG "Enable schnorrsig module." ON) +if(SECP256K1_ENABLE_MODULE_SCHNORRSIG) + set(SECP256K1_ENABLE_MODULE_EXTRAKEYS ON) + add_definitions(-DENABLE_MODULE_SCHNORRSIG=1) +endif() +if(SECP256K1_ENABLE_MODULE_EXTRAKEYS) + add_definitions(-DENABLE_MODULE_EXTRAKEYS=1) +endif() + +option(SECP256K1_USE_EXTERNAL_DEFAULT_CALLBACKS "Enable external default callback functions." OFF) +if(SECP256K1_USE_EXTERNAL_DEFAULT_CALLBACKS) + add_definitions(-DUSE_EXTERNAL_DEFAULT_CALLBACKS=1) +endif() + +set(SECP256K1_ECMULT_WINDOW_SIZE "AUTO" CACHE STRING "Window size for ecmult precomputation for verification, specified as integer in range [2..24]. \"AUTO\" is a reasonable setting for desktop machines (currently 15). [default=AUTO]") +set_property(CACHE SECP256K1_ECMULT_WINDOW_SIZE PROPERTY STRINGS "AUTO" 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24) +include(CheckStringOptionValue) +check_string_option_value(SECP256K1_ECMULT_WINDOW_SIZE) +if(SECP256K1_ECMULT_WINDOW_SIZE STREQUAL "AUTO") + set(SECP256K1_ECMULT_WINDOW_SIZE 15) +endif() +add_definitions(-DECMULT_WINDOW_SIZE=${SECP256K1_ECMULT_WINDOW_SIZE}) + +set(SECP256K1_ECMULT_GEN_PREC_BITS "AUTO" CACHE STRING "Precision bits to tune the precomputed table size for signing, specified as integer 2, 4 or 8. \"AUTO\" is a reasonable setting for desktop machines (currently 4). [default=AUTO]") +set_property(CACHE SECP256K1_ECMULT_GEN_PREC_BITS PROPERTY STRINGS "AUTO" 2 4 8) +check_string_option_value(SECP256K1_ECMULT_GEN_PREC_BITS) +if(SECP256K1_ECMULT_GEN_PREC_BITS STREQUAL "AUTO") + set(SECP256K1_ECMULT_GEN_PREC_BITS 4) +endif() +add_definitions(-DECMULT_GEN_PREC_BITS=${SECP256K1_ECMULT_GEN_PREC_BITS}) + +set(SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY "OFF" CACHE STRING "Test-only override of the (autodetected by the C code) \"widemul\" setting. Legal values are: \"OFF\", \"int128_struct\", \"int128\" or \"int64\". [default=OFF]") +set_property(CACHE SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY PROPERTY STRINGS "OFF" "int128_struct" "int128" "int64") +check_string_option_value(SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY) +if(SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY) + string(TOUPPER "${SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY}" widemul_upper_value) + add_definitions(-DUSE_FORCE_WIDEMUL_${widemul_upper_value}=1) +endif() +mark_as_advanced(FORCE SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY) + +set(SECP256K1_ASM "AUTO" CACHE STRING "Assembly optimizations to use: \"AUTO\", \"OFF\", \"x86_64\" or \"arm\" (experimental). [default=AUTO]") +set_property(CACHE SECP256K1_ASM PROPERTY STRINGS "AUTO" "OFF" "x86_64" "arm") +check_string_option_value(SECP256K1_ASM) +if(SECP256K1_ASM STREQUAL "arm") + enable_language(ASM) + add_definitions(-DUSE_EXTERNAL_ASM=1) +elseif(SECP256K1_ASM) + include(Check64bitAssembly) + check_64bit_assembly() + if(HAS_64BIT_ASM) + set(SECP256K1_ASM "x86_64") + add_definitions(-DUSE_ASM_X86_64=1) + elseif(SECP256K1_ASM STREQUAL "AUTO") + set(SECP256K1_ASM "OFF") + else() + message(FATAL_ERROR "x86_64 assembly optimization requested but not available.") + endif() +endif() + +option(SECP256K1_EXPERIMENTAL "Allow experimental configuration options." OFF) +if(NOT SECP256K1_EXPERIMENTAL) + if(SECP256K1_ASM STREQUAL "arm") + message(FATAL_ERROR "ARM assembly optimization is experimental. Use -DSECP256K1_EXPERIMENTAL=ON to allow.") + endif() +endif() + +set(SECP256K1_VALGRIND "AUTO" CACHE STRING "Build with extra checks for running inside Valgrind. [default=AUTO]") +set_property(CACHE SECP256K1_VALGRIND PROPERTY STRINGS "AUTO" "OFF" "ON") +check_string_option_value(SECP256K1_VALGRIND) +if(SECP256K1_VALGRIND) + find_package(Valgrind MODULE) + if(Valgrind_FOUND) + set(SECP256K1_VALGRIND ON) + include_directories(${Valgrind_INCLUDE_DIR}) + add_definitions(-DVALGRIND) + elseif(SECP256K1_VALGRIND STREQUAL "AUTO") + set(SECP256K1_VALGRIND OFF) + else() + message(FATAL_ERROR "Valgrind support requested but valgrind/memcheck.h header not available.") + endif() +endif() + +option(SECP256K1_BUILD_BENCHMARK "Build benchmarks." ON) +option(SECP256K1_BUILD_TESTS "Build tests." ON) +option(SECP256K1_BUILD_EXHAUSTIVE_TESTS "Build exhaustive tests." ON) +option(SECP256K1_BUILD_CTIME_TESTS "Build constant-time tests." ${SECP256K1_VALGRIND}) +option(SECP256K1_BUILD_EXAMPLES "Build examples." OFF) + +# Redefine configuration flags. +# We leave assertions on, because they are only used in the examples, and we want them always on there. +if(MSVC) + string(REGEX REPLACE "/DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}") + string(REGEX REPLACE "/DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}") + string(REGEX REPLACE "/DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL}") +else() + string(REGEX REPLACE "-DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}") + string(REGEX REPLACE "-DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}") + string(REGEX REPLACE "-DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL}") + # Prefer -O2 optimization level. (-O3 is CMake's default for Release for many compilers.) + string(REGEX REPLACE "-O3[ \t\r\n]*" "-O2" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}") +endif() + +# Define custom "Coverage" build type. +set(CMAKE_C_FLAGS_COVERAGE "${CMAKE_C_FLAGS_RELWITHDEBINFO} -O0 -DCOVERAGE=1 --coverage -Wno-unused-parameter" CACHE STRING + "Flags used by the C compiler during \"Coverage\" builds." + FORCE +) +set(CMAKE_EXE_LINKER_FLAGS_COVERAGE "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO} --coverage" CACHE STRING + "Flags used for linking binaries during \"Coverage\" builds." + FORCE +) +set(CMAKE_SHARED_LINKER_FLAGS_COVERAGE "${CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO} --coverage" CACHE STRING + "Flags used by the shared libraries linker during \"Coverage\" builds." + FORCE +) +mark_as_advanced( + CMAKE_C_FLAGS_COVERAGE + CMAKE_EXE_LINKER_FLAGS_COVERAGE + CMAKE_SHARED_LINKER_FLAGS_COVERAGE +) + +if(CMAKE_CONFIGURATION_TYPES) + set(CMAKE_CONFIGURATION_TYPES "RelWithDebInfo" "Release" "Debug" "MinSizeRel" "Coverage") +endif() + +get_property(cached_cmake_build_type CACHE CMAKE_BUILD_TYPE PROPERTY TYPE) +if(cached_cmake_build_type) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY + STRINGS "RelWithDebInfo" "Release" "Debug" "MinSizeRel" "Coverage" + ) +endif() + +set(default_build_type "RelWithDebInfo") +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + message(STATUS "Setting build type to \"${default_build_type}\" as none was specified") + set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE STRING "Choose the type of build." FORCE) +endif() + +include(TryAddCompileOption) +if(MSVC) + try_add_compile_option(/W2) + try_add_compile_option(/wd4146) +else() + try_add_compile_option(-pedantic) + try_add_compile_option(-Wall) + try_add_compile_option(-Wcast-align) + try_add_compile_option(-Wcast-align=strict) + try_add_compile_option(-Wconditional-uninitialized) + try_add_compile_option(-Wextra) + try_add_compile_option(-Wnested-externs) + try_add_compile_option(-Wno-long-long) + try_add_compile_option(-Wno-overlength-strings) + try_add_compile_option(-Wno-unused-function) + try_add_compile_option(-Wreserved-identifier) + try_add_compile_option(-Wshadow) + try_add_compile_option(-Wstrict-prototypes) + try_add_compile_option(-Wundef) +endif() + +if(CMAKE_VERSION VERSION_GREATER 3.2) + # Honor visibility properties for all target types. + # See: https://cmake.org/cmake/help/latest/policy/CMP0063.html + cmake_policy(SET CMP0063 NEW) +endif() +set(CMAKE_C_VISIBILITY_PRESET hidden) + +# Ask CTest to create a "check" target (e.g., make check) as alias for the "test" target. +# CTEST_TEST_TARGET_ALIAS is not documented but supposed to be user-facing. +# See: https://gitlab.kitware.com/cmake/cmake/-/commit/816c9d1aa1f2b42d40c81a991b68c96eb12b6d2 +set(CTEST_TEST_TARGET_ALIAS check) +include(CTest) +# We do not use CTest's BUILD_TESTING because a single toggle for all tests is too coarse for our needs. +mark_as_advanced(BUILD_TESTING) +if(SECP256K1_BUILD_BENCHMARK OR SECP256K1_BUILD_TESTS OR SECP256K1_BUILD_EXHAUSTIVE_TESTS OR SECP256K1_BUILD_CTIME_TESTS OR SECP256K1_BUILD_EXAMPLES) + enable_testing() +endif() + +add_subdirectory(src) +if(SECP256K1_BUILD_EXAMPLES) + add_subdirectory(examples) +endif() + +message("\n") +message("secp256k1 configure summary") +message("===========================") +message("Build artifacts:") +message(" shared library ...................... ${SECP256K1_BUILD_SHARED}") +message(" static library ...................... ${SECP256K1_BUILD_STATIC}") +message("Optional modules:") +message(" ECDH ................................ ${SECP256K1_ENABLE_MODULE_ECDH}") +message(" ECDSA pubkey recovery ............... ${SECP256K1_ENABLE_MODULE_RECOVERY}") +message(" extrakeys ........................... ${SECP256K1_ENABLE_MODULE_EXTRAKEYS}") +message(" schnorrsig .......................... ${SECP256K1_ENABLE_MODULE_SCHNORRSIG}") +message("Parameters:") +message(" ecmult window size .................. ${SECP256K1_ECMULT_WINDOW_SIZE}") +message(" ecmult gen precision bits ........... ${SECP256K1_ECMULT_GEN_PREC_BITS}") +message("Optional features:") +message(" assembly optimization ............... ${SECP256K1_ASM}") +message(" external callbacks .................. ${SECP256K1_USE_EXTERNAL_DEFAULT_CALLBACKS}") +if(SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY) + message(" wide multiplication (test-only) ..... ${SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY}") +endif() +message("Optional binaries:") +message(" benchmark ........................... ${SECP256K1_BUILD_BENCHMARK}") +message(" noverify_tests ...................... ${SECP256K1_BUILD_TESTS}") +set(tests_status "${SECP256K1_BUILD_TESTS}") +if(CMAKE_BUILD_TYPE STREQUAL "Coverage") + set(tests_status OFF) +endif() +message(" tests ............................... ${tests_status}") +message(" exhaustive tests .................... ${SECP256K1_BUILD_EXHAUSTIVE_TESTS}") +message(" ctime_tests ......................... ${SECP256K1_BUILD_CTIME_TESTS}") +message(" examples ............................ ${SECP256K1_BUILD_EXAMPLES}") +message("") +if(CMAKE_CROSSCOMPILING) + set(cross_status "TRUE, for ${CMAKE_SYSTEM_NAME}, ${CMAKE_SYSTEM_PROCESSOR}") +else() + set(cross_status "FALSE") +endif() +message("Cross compiling ....................... ${cross_status}") +message("Valgrind .............................. ${SECP256K1_VALGRIND}") +get_directory_property(definitions COMPILE_DEFINITIONS) +string(REPLACE ";" " " definitions "${definitions}") +message("Preprocessor defined macros ........... ${definitions}") +message("C compiler ............................ ${CMAKE_C_COMPILER}") +message("CFLAGS ................................ ${CMAKE_C_FLAGS}") +get_directory_property(compile_options COMPILE_OPTIONS) +string(REPLACE ";" " " compile_options "${compile_options}") +message("Compile options ....................... " ${compile_options}) +if(DEFINED CMAKE_BUILD_TYPE) + message("Build type:") + message(" - CMAKE_BUILD_TYPE ................... ${CMAKE_BUILD_TYPE}") + string(TOUPPER "${CMAKE_BUILD_TYPE}" build_type) + message(" - CFLAGS ............................. ${CMAKE_C_FLAGS_${build_type}}") + message(" - LDFLAGS for executables ............ ${CMAKE_EXE_LINKER_FLAGS_${build_type}}") + message(" - LDFLAGS for shared libraries ....... ${CMAKE_SHARED_LINKER_FLAGS_${build_type}}") +else() + message("Available configurations .............. ${CMAKE_CONFIGURATION_TYPES}") + message("RelWithDebInfo configuration:") + message(" - CFLAGS ............................. ${CMAKE_C_FLAGS_RELWITHDEBINFO}") + message(" - LDFLAGS for executables ............ ${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO}") + message(" - LDFLAGS for shared libraries ....... ${CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO}") + message("Debug configuration:") + message(" - CFLAGS ............................. ${CMAKE_C_FLAGS_DEBUG}") + message(" - LDFLAGS for executables ............ ${CMAKE_EXE_LINKER_FLAGS_DEBUG}") + message(" - LDFLAGS for shared libraries ....... ${CMAKE_SHARED_LINKER_FLAGS_DEBUG}") +endif() +message("\n") +if(SECP256K1_EXPERIMENTAL) + message( + " ******\n" + " WARNING: experimental build\n" + " Experimental features do not have stable APIs or properties, and may not be safe for production use.\n" + " ******\n" + ) +endif() diff --git a/README.md b/README.md index ffdc9aeaee..6edd52a89a 100644 --- a/README.md +++ b/README.md @@ -60,10 +60,8 @@ Implementation details * Optional runtime blinding which attempts to frustrate differential power analysis. * The precomputed tables add and eventually subtract points for which no known scalar (secret key) is known, preventing even an attacker with control over the secret key used to control the data internally. -Build steps ------------ - -libsecp256k1 is built using autotools: +Building with Autotools +----------------------- $ ./autogen.sh $ ./configure @@ -73,6 +71,43 @@ libsecp256k1 is built using autotools: To compile optional modules (such as Schnorr signatures), you need to run `./configure` with additional flags (such as `--enable-module-schnorrsig`). Run `./configure --help` to see the full list of available flags. +Building with CMake (experimental) +---------------------------------- + +To maintain a pristine source tree, CMake encourages to perform an out-of-source build by using a separate dedicated build tree. + +### Building on POSIX systems + + $ mkdir build && cd build + $ cmake .. + $ make + $ make check # run the test suite + $ sudo make install # optional + +To compile optional modules (such as Schnorr signatures), you need to run `cmake` with additional flags (such as `-DSECP256K1_ENABLE_MODULE_SCHNORRSIG=ON`). Run `cmake .. -LH` to see the full list of available flags. + +### Cross compiling + +To alleviate issues with cross compiling, preconfigured toolchain files are available in the `cmake` directory. +For example, to cross compile for Windows: + + $ cmake .. -DCMAKE_TOOLCHAIN_FILE=../cmake/x86_64-w64-mingw32.toolchain.cmake + +To cross compile for Android with [NDK](https://developer.android.com/ndk/guides/cmake) (using NDK's toolchain file, and assuming the `ANDROID_NDK_ROOT` environment variable has been set): + + $ cmake .. -DCMAKE_TOOLCHAIN_FILE="${ANDROID_NDK_ROOT}/build/cmake/android.toolchain.cmake" -DANDROID_ABI=arm64-v8a -DANDROID_PLATFORM=28 + +### Building on Windows + +To build on Windows with Visual Studio, a proper [generator](https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html#visual-studio-generators) must be specified for a new build tree. + +The following example assumes using of Visual Studio 2022 and CMake v3.21+. + +In "Developer Command Prompt for VS 2022": + + >cmake -G "Visual Studio 17 2022" -A x64 -S . -B build + >cmake --build build --config Release + Usage examples ----------- Usage examples can be found in the [examples](examples) directory. To compile them you need to configure with `--enable-examples`. diff --git a/cmake/Check64bitAssembly.cmake b/cmake/Check64bitAssembly.cmake new file mode 100644 index 0000000000..3f65887765 --- /dev/null +++ b/cmake/Check64bitAssembly.cmake @@ -0,0 +1,14 @@ +include(CheckCSourceCompiles) + +function(check_64bit_assembly) + 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\"); + } + " HAS_64BIT_ASM) + set(HAS_64BIT_ASM ${HAS_64BIT_ASM} PARENT_SCOPE) +endfunction() diff --git a/cmake/CheckStringOptionValue.cmake b/cmake/CheckStringOptionValue.cmake new file mode 100644 index 0000000000..bc4d7b5749 --- /dev/null +++ b/cmake/CheckStringOptionValue.cmake @@ -0,0 +1,12 @@ +function(check_string_option_value option) + get_property(expected_values CACHE ${option} PROPERTY STRINGS) + if(expected_values) + foreach(value IN LISTS expected_values) + if(value STREQUAL "${${option}}") + return() + endif() + endforeach() + message(FATAL_ERROR "${option} value is \"${${option}}\", but must be one of ${expected_values}.") + endif() + message(AUTHOR_WARNING "The STRINGS property must be set before invoking `check_string_option_value' function.") +endfunction() diff --git a/cmake/FindValgrind.cmake b/cmake/FindValgrind.cmake new file mode 100644 index 0000000000..f6c1f58649 --- /dev/null +++ b/cmake/FindValgrind.cmake @@ -0,0 +1,41 @@ +if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin") + find_program(BREW_COMMAND brew) + execute_process( + COMMAND ${BREW_COMMAND} --prefix valgrind + OUTPUT_VARIABLE valgrind_brew_prefix + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE + ) +endif() + +set(hints_paths) +if(valgrind_brew_prefix) + set(hints_paths ${valgrind_brew_prefix}/include) +endif() + +find_path(Valgrind_INCLUDE_DIR + NAMES valgrind/memcheck.h + HINTS ${hints_paths} +) + +if(Valgrind_INCLUDE_DIR) + include(CheckCSourceCompiles) + set(CMAKE_REQUIRED_INCLUDES ${Valgrind_INCLUDE_DIR}) + check_c_source_compiles(" + #include + #if defined(NVALGRIND) + # error \"Valgrind does not support this platform.\" + #endif + + int main() {} + " Valgrind_WORKS) +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(Valgrind + REQUIRED_VARS Valgrind_INCLUDE_DIR Valgrind_WORKS +) + +mark_as_advanced( + Valgrind_INCLUDE_DIR +) diff --git a/cmake/TryAddCompileOption.cmake b/cmake/TryAddCompileOption.cmake new file mode 100644 index 0000000000..f53c252c2d --- /dev/null +++ b/cmake/TryAddCompileOption.cmake @@ -0,0 +1,23 @@ +include(CheckCCompilerFlag) + +function(try_add_compile_option option) + string(MAKE_C_IDENTIFIER ${option} result) + string(TOUPPER ${result} result) + set(result "C_SUPPORTS${result}") + set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) + if(NOT MSVC) + set(CMAKE_REQUIRED_FLAGS "-Werror") + endif() + check_c_compiler_flag(${option} ${result}) + if(${result}) + get_property(compile_options + DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + PROPERTY COMPILE_OPTIONS + ) + list(APPEND compile_options "${option}") + set_property( + DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + PROPERTY COMPILE_OPTIONS "${compile_options}" + ) + endif() +endfunction() diff --git a/cmake/arm-linux-gnueabihf.toolchain.cmake b/cmake/arm-linux-gnueabihf.toolchain.cmake new file mode 100644 index 0000000000..0d91912b6d --- /dev/null +++ b/cmake/arm-linux-gnueabihf.toolchain.cmake @@ -0,0 +1,3 @@ +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSTEM_PROCESSOR arm) +set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc) diff --git a/cmake/config.cmake.in b/cmake/config.cmake.in new file mode 100644 index 0000000000..46b180ab19 --- /dev/null +++ b/cmake/config.cmake.in @@ -0,0 +1,5 @@ +@PACKAGE_INIT@ + +include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@-targets.cmake") + +check_required_components(@PROJECT_NAME@) diff --git a/cmake/x86_64-w64-mingw32.toolchain.cmake b/cmake/x86_64-w64-mingw32.toolchain.cmake new file mode 100644 index 0000000000..96119b72d1 --- /dev/null +++ b/cmake/x86_64-w64-mingw32.toolchain.cmake @@ -0,0 +1,3 @@ +set(CMAKE_SYSTEM_NAME Windows) +set(CMAKE_SYSTEM_PROCESSOR x86_64) +set(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt new file mode 100644 index 0000000000..9a2fc51bf9 --- /dev/null +++ b/examples/CMakeLists.txt @@ -0,0 +1,34 @@ +add_library(example INTERFACE) +target_include_directories(example INTERFACE + ${PROJECT_SOURCE_DIR}/include +) +target_compile_options(example INTERFACE + $<$:/wd4005> +) +target_link_libraries(example INTERFACE + $<$:bcrypt> +) +if(SECP256K1_BUILD_SHARED) + target_link_libraries(example INTERFACE ${PROJECT_NAME}) +elseif(SECP256K1_BUILD_STATIC) + target_link_libraries(example INTERFACE ${PROJECT_NAME}_static) + if(MSVC) + target_link_options(example INTERFACE /IGNORE:4217) + endif() +endif() + +add_executable(ecdsa_example ecdsa.c) +target_link_libraries(ecdsa_example example) +add_test(ecdsa_example ecdsa_example) + +if(SECP256K1_ENABLE_MODULE_ECDH) + add_executable(ecdh_example ecdh.c) + target_link_libraries(ecdh_example example) + add_test(ecdh_example ecdh_example) +endif() + +if(SECP256K1_ENABLE_MODULE_SCHNORRSIG) + add_executable(schnorr_example schnorr.c) + target_link_libraries(schnorr_example example) + add_test(schnorr_example schnorr_example) +endif() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000000..f11005294e --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,151 @@ +# Must be included before CMAKE_INSTALL_INCLUDEDIR is used. +include(GNUInstallDirs) +set(${PROJECT_NAME}_installables "") + +if(SECP256K1_ASM STREQUAL "arm") + add_library(common OBJECT + asm/field_10x26_arm.s + ) + set(common_obj "$") +else() + set(common_obj "") +endif() + +add_library(precomputed OBJECT + precomputed_ecmult.c + precomputed_ecmult_gen.c +) +set(internal_obj "$" "${common_obj}") + +add_library(${PROJECT_NAME} SHARED EXCLUDE_FROM_ALL + secp256k1.c + ${internal_obj} +) +target_include_directories(${PROJECT_NAME} INTERFACE + $ +) +target_compile_definitions(${PROJECT_NAME} PRIVATE + $<$:DLL_EXPORT> +) +set_target_properties(${PROJECT_NAME} PROPERTIES + VERSION "${${PROJECT_NAME}_LIB_VERSION_CURRENT}.${${PROJECT_NAME}_LIB_VERSION_AGE}.${${PROJECT_NAME}_LIB_VERSION_REVISION}" + SOVERSION "${${PROJECT_NAME}_LIB_VERSION_CURRENT}" +) +if(SECP256K1_BUILD_SHARED) + get_target_property(use_pic ${PROJECT_NAME} POSITION_INDEPENDENT_CODE) + set_target_properties(precomputed PROPERTIES POSITION_INDEPENDENT_CODE ${use_pic}) + set_target_properties(${PROJECT_NAME} PROPERTIES EXCLUDE_FROM_ALL FALSE) + list(APPEND ${PROJECT_NAME}_installables ${PROJECT_NAME}) +endif() + +add_library(${PROJECT_NAME}_static STATIC EXCLUDE_FROM_ALL + secp256k1.c + ${internal_obj} +) +target_include_directories(${PROJECT_NAME}_static INTERFACE + $ +) +if(NOT MSVC) + set_target_properties(${PROJECT_NAME}_static PROPERTIES + OUTPUT_NAME ${PROJECT_NAME} + ) +endif() +if(SECP256K1_BUILD_STATIC) + set_target_properties(${PROJECT_NAME}_static PROPERTIES EXCLUDE_FROM_ALL FALSE) + list(APPEND ${PROJECT_NAME}_installables ${PROJECT_NAME}_static) +endif() + +add_library(binary_interface INTERFACE) +target_compile_definitions(binary_interface INTERFACE + $<$:_CRT_SECURE_NO_WARNINGS> +) + +add_library(link_library INTERFACE) +if(SECP256K1_BUILD_SHARED) + target_link_libraries(link_library INTERFACE ${PROJECT_NAME}) +elseif(SECP256K1_BUILD_STATIC) + target_link_libraries(link_library INTERFACE ${PROJECT_NAME}_static) +endif() + +if(SECP256K1_BUILD_BENCHMARK) + add_executable(bench bench.c) + target_link_libraries(bench binary_interface link_library) + add_executable(bench_internal bench_internal.c ${internal_obj}) + target_link_libraries(bench_internal binary_interface) + add_executable(bench_ecmult bench_ecmult.c ${internal_obj}) + target_link_libraries(bench_ecmult binary_interface) +endif() + +if(SECP256K1_BUILD_TESTS) + add_executable(noverify_tests tests.c ${internal_obj}) + target_link_libraries(noverify_tests binary_interface) + add_test(noverify_tests noverify_tests) + if(NOT CMAKE_BUILD_TYPE STREQUAL "Coverage") + add_executable(tests tests.c ${internal_obj}) + target_compile_definitions(tests PRIVATE VERIFY) + target_link_libraries(tests binary_interface) + add_test(tests tests) + endif() +endif() + +if(SECP256K1_BUILD_EXHAUSTIVE_TESTS) + # Note: do not include $ in exhaustive_tests (it uses runtime-generated tables). + add_executable(exhaustive_tests tests_exhaustive.c ${common_obj}) + target_compile_definitions(exhaustive_tests PRIVATE $<$>:VERIFY>) + target_link_libraries(exhaustive_tests binary_interface) + add_test(exhaustive_tests exhaustive_tests) +endif() + +if(SECP256K1_BUILD_CTIME_TESTS) + add_executable(ctime_tests ctime_tests.c) + target_link_libraries(ctime_tests binary_interface link_library) +endif() + +install(TARGETS ${${PROJECT_NAME}_installables} + EXPORT ${PROJECT_NAME}-targets + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} +) +set(${PROJECT_NAME}_headers + "${PROJECT_SOURCE_DIR}/include/secp256k1.h" + "${PROJECT_SOURCE_DIR}/include/secp256k1_preallocated.h" +) +if(SECP256K1_ENABLE_MODULE_ECDH) + list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_ecdh.h") +endif() +if(SECP256K1_ENABLE_MODULE_RECOVERY) + list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_recovery.h") +endif() +if(SECP256K1_ENABLE_MODULE_EXTRAKEYS) + list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_extrakeys.h") +endif() +if(SECP256K1_ENABLE_MODULE_SCHNORRSIG) + list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_schnorrsig.h") +endif() +install(FILES ${${PROJECT_NAME}_headers} + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} +) + +install(EXPORT ${PROJECT_NAME}-targets + FILE ${PROJECT_NAME}-targets.cmake + NAMESPACE ${PROJECT_NAME}:: + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME} +) + +include(CMakePackageConfigHelpers) +configure_package_config_file( + ${PROJECT_SOURCE_DIR}/cmake/config.cmake.in + ${PROJECT_NAME}-config.cmake + INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME} + NO_SET_AND_CHECK_MACRO +) +write_basic_package_version_file(${PROJECT_NAME}-config-version.cmake + COMPATIBILITY SameMajorVersion +) +install( + FILES + ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake + ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME} +)