diff --git a/.arclint b/.arclint index 3d82a9867..78dba6e6c 100644 --- a/.arclint +++ b/.arclint @@ -1,295 +1,296 @@ { "linters": { "generated": { "type": "generated" }, "clang-format": { "type": "clang-format", "version": ">=8.0", "bin": ["clang-format-8", "clang-format"], "include": "(^src/.*\\.(h|c|cpp|mm)$)", "exclude": [ "(^src/(secp256k1|univalue|leveldb)/)", "(^src/bench/nanobench.h$)" ] }, "autopep8": { "type": "autopep8", "version": ">=1.3.4", "include": "(\\.py$)", "exclude": [ "(^contrib/gitian-builder/)", "(^contrib/apple-sdk-tools/)" ], "flags": [ "--aggressive", "--ignore=W503,W504" ] }, "flake8": { "type": "flake8", "version": ">=3.0", "include": "(\\.py$)", "exclude": [ "(^contrib/gitian-builder/)", "(^contrib/apple-sdk-tools/)" ], "flags": [ "--ignore=E501,E704,W503,W504" ] }, "lint-format-strings": { "type": "lint-format-strings", "include": "(^src/.*\\.(h|c|cpp)$)", "exclude": [ "(^src/(secp256k1|univalue|leveldb)/)", "(^src/bench/nanobench.h$)", "(^src/test/fuzz/strprintf.cpp$)" ] }, "check-doc": { "type": "check-doc", "include": "(^src/.*\\.(h|c|cpp)$)" }, "lint-tests": { "type": "lint-tests", "include": "(^src/(seeder/|rpc/|wallet/)?test/.*\\.(cpp)$)" }, "lint-python-format": { "type": "lint-python-format", "include": "(\\.py$)", "exclude": [ "(^test/lint/lint-python-format\\.py$)", "(^contrib/gitian-builder/)", "(^contrib/apple-sdk-tools/)" ] }, "phpcs": { "type": "phpcs", "include": "(\\.php$)", "exclude": [ "(^arcanist/__phutil_library_.+\\.php$)" ], "phpcs.standard": "arcanist/phpcs.xml" }, "lint-locale-dependence": { "type": "lint-locale-dependence", "include": "(^src/.*\\.(h|cpp)$)", "exclude": [ "(^src/(crypto/ctaes/|leveldb/|secp256k1/|tinyformat.h|univalue/))", "(^src/bench/nanobench.h$)" ] }, "lint-cheader": { "type": "lint-cheader", "include": "(^src/.*\\.(h|cpp)$)", "exclude": [ "(^src/(crypto/ctaes|secp256k1|univalue|leveldb)/)", "(^src/bench/nanobench.h$)" ] }, "spelling": { "type": "spelling", "exclude": [ "(^build-aux/m4/)", "(^depends/)", "(^doc/release-notes/)", "(^contrib/gitian-builder/)", "(^src/(qt/locale|secp256k1|univalue|leveldb)/)", "(^test/lint/dictionary/)" ], "spelling.dictionaries": [ "test/lint/dictionary/english.json" ] }, "lint-assert-with-side-effects": { "type": "lint-assert-with-side-effects", "include": "(^src/.*\\.(h|cpp)$)", "exclude": [ "(^src/(secp256k1|univalue|leveldb)/)", "(^src/bench/nanobench.h$)" ] }, "lint-include-quotes": { "type": "lint-include-quotes", "include": "(^src/.*\\.(h|cpp)$)", "exclude": [ "(^src/(secp256k1|univalue|leveldb)/)", "(^src/bench/nanobench.h$)" ] }, "lint-include-guard": { "type": "lint-include-guard", "include": "(^src/.*\\.h$)", "exclude": [ "(^src/(crypto/ctaes|secp256k1|univalue|leveldb)/)", "(^src/bench/nanobench.h$)", "(^src/tinyformat.h$)" ] }, "lint-include-source": { "type": "lint-include-source", "include": "(^src/.*\\.(h|c|cpp)$)", "exclude": [ "(^src/(secp256k1|univalue|leveldb)/)", "(^src/bench/nanobench.h$)" ] }, "lint-stdint": { "type": "lint-stdint", "include": "(^src/.*\\.(h|c|cpp)$)", "exclude": [ "(^src/(secp256k1|univalue|leveldb)/)", "(^src/bench/nanobench.h$)", "(^src/compat/assumptions.h$)" ] }, "lint-source-filename": { "type": "lint-source-filename", "include": "(^src/.*\\.(h|c|cpp)$)", "exclude": [ "(^src/(secp256k1|univalue|leveldb)/)", "(^src/bench/nanobench.h$)" ] }, "lint-boost-dependencies": { "type": "lint-boost-dependencies", "include": "(^src/.*\\.(h|cpp)$)" }, "check-rpc-mappings": { "type": "check-rpc-mappings", "include": "(^src/(rpc/|wallet/rpc).*\\.cpp$)" }, "lint-python-encoding": { "type": "lint-python-encoding", "include": "(\\.py$)", "exclude": [ "(^contrib/gitian-builder/)", "(^contrib/apple-sdk-tools/)" ] }, "lint-python-shebang": { "type": "lint-python-shebang", "include": "(\\.py$)", "exclude": [ "(__init__\\.py$)", "(^contrib/gitian-builder/)", "(^contrib/apple-sdk-tools/)" ] }, "lint-bash-shebang": { "type": "lint-bash-shebang", "include": "(\\.sh$)", "exclude": [ "(^contrib/gitian-builder/)" ] }, "shellcheck": { "type": "shellcheck", "version": ">=0.7.0", "flags": [ "--external-sources", "--source-path=SCRIPTDIR" ], "include": "(\\.sh$)", "exclude": [ "(^contrib/gitian-builder/)", "(^src/(secp256k1|univalue)/)" ] }, "lint-shell-locale": { "type": "lint-shell-locale", "include": "(\\.sh$)", "exclude": [ "(^contrib/gitian-builder/)", "(^src/(secp256k1|univalue)/)", "(^cmake/utils/log-and-print-on-failure.sh)" ] }, "lint-cpp-void-parameters": { "type": "lint-cpp-void-parameters", "include": "(^src/.*\\.(h|cpp)$)", "exclude": [ "(^src/(crypto/ctaes|secp256k1|univalue|leveldb)/)", "(^src/bench/nanobench.h$)", "(^src/compat/glibc_compat.cpp$)" ] }, "lint-logs": { "type": "lint-logs", "include": "(^src/.*\\.(h|cpp)$)" }, "lint-qt": { "type": "lint-qt", "include": "(^src/qt/.*\\.(h|cpp)$)", "exclude": [ "(^src/qt/(locale|forms|res)/)" ] }, "lint-doxygen": { "type": "lint-doxygen", "include": "(^src/.*\\.(h|c|cpp)$)", "exclude": [ "(^src/(crypto/ctaes|secp256k1|univalue|leveldb)/)", "(^src/bench/nanobench.h$)" ] }, "lint-whitespace": { "type": "lint-whitespace", "include": "(\\.(ac|am|cmake|conf|in|include|json|m4|md|openrc|php|pl|sh|txt|yml)$)", "exclude": [ "(^contrib/gitian-builder/)", "(^src/(secp256k1|univalue|leveldb)/)", "(^src/bench/nanobench.h$)" ] }, "lint-cppcheck": { "type": "lint-cppcheck", "include": "(^src/.*\\.(h|c|cpp)$)", "exclude": [ "(^src/(crypto/ctaes|secp256k1|univalue|leveldb)/)", "(^src/bench/nanobench.h$)" ] }, "yamllint": { "type": "yamllint", - "include": "(\\.(yml|yaml)$)" + "include": "(\\.(yml|yaml)$)", + "exclude": "(^src/(secp256k1|univalue|leveldb)/)" }, "lint-check-nonfatal": { "type": "lint-check-nonfatal", "include": [ "(^src/rpc/.*\\.(h|c|cpp)$)", "(^src/wallet/rpc*.*\\.(h|c|cpp)$)" ], "exclude": "(^src/rpc/server.cpp)" }, "lint-markdown": { "type": "lint-markdown", "include": [ "(\\.md$)" ], "exclude": "(^contrib/gitian-builder/)" }, "lint-python-mypy": { "type": "lint-python-mypy", "include": "(\\.py$)", "exclude": "(^contrib/)", "flags": [ "--ignore-missing-imports" ] }, "lint-python-mutable-default": { "type": "lint-python-mutable-default", "include": "(\\.py$)", "exclude": [ "(^contrib/gitian-builder/)", "(^contrib/apple-sdk-tools/)" ] }, "prettier": { "type": "prettier", "include": "(^web/.*\\.(css|html|js|json|jsx|md|scss|ts|tsx)$)", "exclude": "(^web/.*/translations/.*\\.json$)" } } } diff --git a/src/secp256k1/.cirrus.yml b/src/secp256k1/.cirrus.yml new file mode 100644 index 000000000..b4819bdcd --- /dev/null +++ b/src/secp256k1/.cirrus.yml @@ -0,0 +1,206 @@ +env: + WIDEMUL: auto + BIGNUM: gmp + STATICPRECOMPUTATION: yes + ECMULTGENPRECISION: auto + ASM: no + AUTOTOOLS_TARGET: check + CMAKE_TARGET: check-secp256k1 + AUTOTOOLS_EXTRA_FLAGS: + CMAKE_EXTRA_FLAGS: + WITH_VALGRIND: yes + RUN_VALGRIND: no + HOST: + ECDH: no + RECOVERY: no + SCHNORR: yes + SCHNORRSIG: no + EXPERIMENTAL: no + JNI: no + OPENSSL_TESTS: auto + MULTISET: no + CTIMETEST: yes + BENCH: yes + ITERS: 2 + # We only need the top commit + CIRRUS_CLONE_DEPTH: 1 + +cat_logs_snippet: &CAT_LOGS + on_failure: + debug_output_script: + - cat config.log || true + - cat test_env.log || true + - env + +task: + timeout_in: 120m + name: "x86_64: Linux (Alpine Linux, Nix Shell)" + container: + dockerfile: ci/linux-nixos.Dockerfile + # Reduce number of CPUs to be able to do more builds in parallel. + cpu: 1 + # More than enough for our scripts. + memory: 1G + matrix: &ENV_MATRIX + - env: {WIDEMUL: int64, RECOVERY: yes} + - env: {WIDEMUL: int64, ECDH: yes, EXPERIMENTAL: yes, MULTISET: yes, SCHNORRSIG: yes} + - env: {WIDEMUL: int128} + - env: {WIDEMUL: int128, RECOVERY: yes, EXPERIMENTAL: yes, SCHNORRSIG: yes} + - env: {WIDEMUL: int128, ECDH: yes, EXPERIMENTAL: yes, MULTISET: yes, SCHNORRSIG: yes} + - env: {WIDEMUL: int128, ASM: x86_64} + - env: {BIGNUM: no} + - env: {BIGNUM: no, RECOVERY: yes, EXPERIMENTAL: yes, MULTISET: yes, SCHNORRSIG: yes} + - env: {BIGNUM: no, STATICPRECOMPUTATION: no} + - env: {AUTOTOOLS_TARGET: distcheck, CMAKE_TARGET: install, WITH_VALGRIND: no, CTIMETEST: no, BENCH: no} + - env: {AUTOTOOLS_EXTRA_FLAGS: CPPFLAGS=-DDETERMINISTIC, CMAKE_EXTRA_FLAGS: -DCMAKE_C_FLAGS=-DDETERMINISTIC} + - env: {AUTOTOOLS_EXTRA_FLAGS: CFLAGS=-O0, CMAKE_EXTRA_FLAGS: -DCMAKE_BUILD_TYPE=Debug, CTIMETEST: no} + - env: {AUTOTOOLS_TARGET: check-java, CMAKE_TARGET: check-secp256k1-java, JNI: yes, ECDH: yes, EXPERIMENTAL: yes, WITH_VALGRIND: no, CTIMETEST: no, BENCH: no} + # The Cirrus macOS VM has no java installed + only_if: $CIRRUS_OS == 'linux' + - env: {SCHNORR: no} + - env: + CFLAGS: "-fsanitize=undefined -fno-omit-frame-pointer" + LDFLAGS: "-fsanitize=undefined -fno-omit-frame-pointer" + UBSAN_OPTIONS: "print_stacktrace=1:halt_on_error=1" + BIGNUM: no + ASM: x86_64 + ECDH: yes + RECOVERY: yes + EXPERIMENTAL: yes + MULTISET: yes + SCHNORRSIG: yes + CTIMETEST: no + - env: { ECMULTGENPRECISION: 2 } + - env: { ECMULTGENPRECISION: 8 } + - env: + RUN_VALGRIND: yes + BIGNUM: no + ASM: x86_64 + ECDH: yes + RECOVERY: yes + EXPERIMENTAL: yes + MULTISET: yes + SCHNORRSIG: yes + OPENSSL_TESTS: no + AUTOTOOLS_TARGET: + CMAKE_TARGET: "secp256k1-tests secp256k1-exhaustive_tests" + matrix: + - env: + CC: gcc + - env: + CC: clang + test_script: + - nix-shell ci/shell.nix --run ./ci/build_autotools.sh + - nix-shell ci/shell.nix --run ./ci/build_cmake.sh + << : *CAT_LOGS + +task: + name: "i686: Linux (Alpine Linux, Nix Shell)" + container: + dockerfile: ci/linux-nixos.Dockerfile + cpu: 1 + memory: 1G + env: + HOST: i686-linux-gnu + ECDH: yes + RECOVERY: yes + EXPERIMENTAL: yes + SCHNORRSIG: yes + OPENSSL_TESTS: no + matrix: + - env: + CC: gcc + - env: + CC: clang + matrix: + - env: + BIGNUM: gmp + - env: + BIGNUM: no + test_script: + - nix-shell ci/shell-i686.nix --run ./ci/build_autotools.sh + - nix-shell ci/shell-i686.nix --run ./ci/build_cmake.sh + << : *CAT_LOGS + +task: + timeout_in: 120m + name: "x86_64: macOS Catalina" + macos_instance: + image: catalina-base + env: + HOMEBREW_NO_AUTO_UPDATE: 1 + HOMEBREW_NO_INSTALL_CLEANUP: 1 + matrix: + << : *ENV_MATRIX + matrix: + - env: + CC: gcc-9 + - env: + CC: clang + # Update Command Line Tools + # Uncomment this if the Command Line Tools on the CirrusCI macOS image are too old to brew valgrind. + # See https://apple.stackexchange.com/a/195963 for the implementation. + ## update_clt_script: + ## - system_profiler SPSoftwareDataType + ## - touch /tmp/.com.apple.dt.CommandLineTools.installondemand.in-progress + ## - |- + ## PROD=$(softwareupdate -l | grep "*.*Command Line" | tail -n 1 | awk -F"*" '{print $2}' | sed -e 's/^ *//' | sed 's/Label: //g' | tr -d '\n') + ## # For debugging + ## - softwareupdate -l && echo "PROD: $PROD" + ## - softwareupdate -i "$PROD" --verbose + ## - rm /tmp/.com.apple.dt.CommandLineTools.installondemand.in-progress + ## + brew_valgrind_pre_script: + - brew config + - brew tap --shallow LouisBrunner/valgrind + # Fetch valgrind source but don't build it yet. + - brew fetch --HEAD LouisBrunner/valgrind/valgrind + brew_valgrind_cache: + # This is $(brew --cellar valgrind) but command substition does not work here. + folder: /usr/local/Cellar/valgrind + # Rebuild cache if ... + fingerprint_script: + # ... macOS version changes: + - sw_vers + # ... brew changes: + - brew config + # ... valgrind changes: + - git -C "$(brew --cache)/valgrind--git" rev-parse HEAD + populate_script: + # If there's no hit in the cache, build and install valgrind. + - brew install --HEAD LouisBrunner/valgrind/valgrind + brew_valgrind_post_script: + # If we have restored valgrind from the cache, tell brew to create symlink to the PATH. + # If we haven't restored from cached (and just run brew install), this is a no-op. + - brew link valgrind + brew_script: + - brew install automake cmake gcc@9 gmp libtool ninja + test_script: + - ./ci/build_autotools.sh + - ./ci/build_cmake.sh + << : *CAT_LOGS + +task: + name: "s390x (big-endian): Linux (Debian QEMU)" + container: + dockerfile: ci/linux-debian-s390-qemu.Dockerfile + cpu: 1 + memory: 1G + env: + QEMU_CMD: qemu-s390x + HOST: s390x-linux-gnu + WITH_VALGRIND: no + BIGNUM: no + ECDH: yes + RECOVERY: yes + EXPERIMENTAL: yes + MULTISET: yes + SCHNORRSIG: yes + OPENSSL_TESTS: no + CTIMETEST: no + AUTOTOOLS_TARGET: + test_script: + # https://sourceware.org/bugzilla/show_bug.cgi?id=27008 + - rm /etc/ld.so.cache + - ./ci/build_autotools.sh + << : *CAT_LOGS diff --git a/src/secp256k1/.travis.yml b/src/secp256k1/.travis.yml deleted file mode 100644 index 96d99e7e7..000000000 --- a/src/secp256k1/.travis.yml +++ /dev/null @@ -1,121 +0,0 @@ -language: c -os: - - linux - - osx - -dist: bionic -# Valgrind currently supports upto macOS 10.13, the latest xcode of that version is 10.1 -osx_image: xcode10.1 -addons: - apt: - packages: - - gcc-multilib - - libc6-dbg:i386 - - libgmp-dev - - libgmp-dev:i386 - - libtool-bin - - ninja-build - - valgrind -install: - - if [ "${TRAVIS_CPU_ARCH}" = "amd64" ]; then ./travis/install_cmake.sh; fi - - if [ "${TRAVIS_OS_NAME}" = "osx" ]; then HOMEBREW_NO_AUTO_UPDATE=1 brew install gcc@9 gmp ninja openssl valgrind; fi -cache: - directories: - - /opt/cmake -compiler: - - clang - - gcc -env: - global: - - WIDEMUL=auto - - BIGNUM=gmp - - STATICPRECOMPUTATION=yes - - ECMULTGENPRECISION=auto - - ASM=no - - AUTOTOOLS_TARGET=check - - CMAKE_TARGET=check-secp256k1 - - AUTOTOOLS_EXTRA_FLAGS= - - CMAKE_EXTRA_FLAGS= - - WITH_VALGRIND=yes - - RUN_VALGRIND=no - - HOST= - - ECDH=no - - RECOVERY=no - - SCHNORR=yes - - SCHNORRSIG=no - - EXPERIMENTAL=no - - JNI=no - - OPENSSL_TESTS=auto - - MULTISET=no - - CTIMETEST=yes - - BENCH=yes - - ITERS=2 - jobs: - - WIDEMUL=int64 RECOVERY=yes - - WIDEMUL=int64 ECDH=yes EXPERIMENTAL=yes MULTISET=yes SCHNORRSIG=yes - - WIDEMUL=int128 - - WIDEMUL=int128 RECOVERY=yes EXPERIMENTAL=yes SCHNORRSIG=yes - - WIDEMUL=int128 ECDH=yes EXPERIMENTAL=yes MULTISET=yes SCHNORRSIG=yes - - WIDEMUL=int128 ASM=x86_64 - - BIGNUM=no - - BIGNUM=no RECOVERY=yes EXPERIMENTAL=yes MULTISET=yes SCHNORRSIG=yes - - BIGNUM=no STATICPRECOMPUTATION=no - - AUTOTOOLS_TARGET=distcheck CMAKE_TARGET=install WITH_VALGRIND=no CTIMETEST=no BENCH=no - - AUTOTOOLS_EXTRA_FLAGS=CPPFLAGS=-DDETERMINISTIC CMAKE_EXTRA_FLAGS=-DCMAKE_C_FLAGS=-DDETERMINISTIC - - AUTOTOOLS_EXTRA_FLAGS=CFLAGS=-O0 CMAKE_EXTRA_FLAGS=-DCMAKE_BUILD_TYPE=Debug CTIMETEST=no - - AUTOTOOLS_TARGET=check-java CMAKE_TARGET=check-secp256k1-java JNI=yes ECDH=yes EXPERIMENTAL=yes WITH_VALGRIND=no CTIMETEST=no BENCH=no - - CFLAGS="-fsanitize=undefined -fno-omit-frame-pointer" LDFLAGS="-fsanitize=undefined -fno-omit-frame-pointer" - UBSAN_OPTIONS="print_stacktrace=1:halt_on_error=1" - BIGNUM=no ASM=x86_64 ECDH=yes RECOVERY=yes EXPERIMENTAL=yes MULTISET=yes SCHNORRSIG=yes CTIMETEST=no - - ECMULTGENPRECISION=2 - - ECMULTGENPRECISION=8 - - RUN_VALGRIND=yes - BIGNUM=no ASM=x86_64 ECDH=yes RECOVERY=yes EXPERIMENTAL=yes SCHNORRSIG=yes MULTISET=yes OPENSSL_TESTS=no - AUTOTOOLS_TARGET= - CMAKE_EXTRA_FLAGS=-DCMAKE_C_FLAGS=-DVALGRIND CMAKE_TARGET="secp256k1-tests secp256k1-exhaustive_tests" - - SCHNORR=no -jobs: - fast_finish: true - include: - - compiler: clang - os: linux - env: HOST=i686-linux-gnu OPENSSL_TESTS=no - - compiler: clang - os: linux - env: HOST=i686-linux-gnu BIGNUM=no OPENSSL_TESTS=no - - compiler: gcc - os: linux - env: HOST=i686-linux-gnu BIGNUM=no OPENSSL_TESTS=no - - compiler: gcc - os: linux - env: HOST=i686-linux-gnu OPENSSL_TESTS=no - # S390x build (big endian system) - - dist: focal - compiler: gcc - env: HOST=s390x-unknown-linux-gnu OPENSSL_TESTS=no ECDH=yes RECOVERY=yes EXPERIMENTAL=yes SCHNORRSIG=yes MULTISET=yes CTIMETEST=no - arch: s390x - addons: - apt: - packages: - - cmake - - libgmp-dev - - libtool-bin - - ninja-build - - valgrind - -before_script: - # This limits the iterations in the benchmarks below to ITER iterations. - - export SECP256K1_BENCH_ITERS="$ITERS" - -# travis auto terminates jobs that go for 10 minutes without printing to stdout, -# but travis_wait doesn't work well with forking programs like valgrind -# (https://docs.travis-ci.com/user/common-build-problems/#build-times-out-because-no-output-was-received https://github.com/bitcoin-core/secp256k1/pull/750#issuecomment-623476860) -script: - - function keep_alive() { while true; do echo -en "\a"; sleep 60; done } - - keep_alive & - - ./travis/build_autotools.sh - - ./travis/build_cmake.sh - - kill %keep_alive - -after_script: - - valgrind --version diff --git a/src/secp256k1/README.md b/src/secp256k1/README.md index e185fe60a..a672db9ed 100644 --- a/src/secp256k1/README.md +++ b/src/secp256k1/README.md @@ -1,146 +1,146 @@ libsecp256k1 ============ -[![Build Status](https://travis-ci.org/bitcoin-abc/secp256k1.svg?branch=master)](https://travis-ci.org/bitcoin-abc/secp256k1) +[![Build Status](https://api.cirrus-ci.com/github/bitcoin-abc/secp256k1.svg?branch=master)](https://cirrus-ci.com/github/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. This library is intended to be the highest quality publicly available library for cryptography on the secp256k1 curve. However, the primary focus of its development has been for usage in the Bitcoin Cash system and usage unlike Bitcoin's may be less well tested, verified, or suffer from a less well thought out interface. Correct usage requires some care and consideration that the library is fit for your application's purpose. 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)). * Additive and multiplicative tweaking of secret/public keys. * Serialization/parsing of secret keys, public keys, signatures. * Constant time, constant memory access signing and pubkey generation. * Derandomized ECDSA (via RFC6979 or with a caller provided function.) * Very efficient implementation. * Suitable for embedded systems. * Optional module for public key recovery. * Optional module for ECDH key exchange. * Optional module for multiset hash (experimental). Experimental features have not received enough scrutiny to satisfy the standard of quality of this library but are made available for testing and review by the community. The APIs of these features should not be considered stable. 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. * 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 (including hand-optimized assembly for 32-bit ARM, by Wladimir J. van der Laan). * 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. * 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 (secret key) is known, preventing even an attacker with control over the secret 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 Test coverage ----------- This library aims to have full coverage of the reachable lines and branches. __To create a test coverage report with autotools:__ Configure with `--enable-coverage` (use of GCC is necessary): $ ./configure --enable-coverage Run the tests: $ make check To create a report, `gcovr` is recommended, as it includes branch coverage reporting: $ gcovr --exclude 'src/bench*' --print-summary To create a HTML report with coloured and annotated source code: $ gcovr --exclude 'src/bench*' --html --html-details -o coverage.html __To create a test coverage report with CMake:__ Make sure you installed the dependencies first, and they are in your `PATH`: `c++filt`, `gcov`, `genhtml`, `lcov` and `python3`. Then run the build, tests and generate the coverage report with: ```bash mkdir coverage cd coverage cmake -GNinja .. \ -DCMAKE_C_COMPILER=gcc \ -DSECP256K1_ENABLE_COVERAGE=ON \ -DSECP256K1_ENABLE_BRANCH_COVERAGE=ON # optional ninja coverage-check-secp256k1 ``` The coverage report will be available by opening the file `check-secp256k1.coverage/index.html` with a web browser. Reporting a vulnerability ------------ See [SECURITY.md](SECURITY.md) diff --git a/src/secp256k1/ci/build_autotools.sh b/src/secp256k1/ci/build_autotools.sh new file mode 100755 index 000000000..a06afb3cb --- /dev/null +++ b/src/secp256k1/ci/build_autotools.sh @@ -0,0 +1,117 @@ +#!/usr/bin/env bash + +export LC_ALL=C + +set -ex + +# FIXME The java tests will fail on macOS with autotools due to the +# libsepc256k1_jni library referencing the libsecp256k1 library with an absolute +# path. This needs to be rewritten with install_name_tool to use relative paths +# via the @variables supported by the macOS loader. +if ["${CIRRUS_OS}" = "darwin"] && [ "$JNI" = "yes" ] +then + echo "Skipping the java tests built with autotools on OSX" + exit 0 +fi + +if [ -n "$HOST" ]; then + USE_HOST="--host=$HOST" +fi + +if [ "x$HOST" = "xi686-linux-gnu" ]; then + CC="$CC -m32" +elif [ "x$HOST" = "xs390x-linux-gnu" ]; then + CC="s390x-linux-gnu-gcc" +fi + +$CC --version + +./autogen.sh + +mkdir buildautotools +pushd buildautotools + +# Nix doesn't store GNU file in /usr/bin, see https://lists.gnu.org/archive/html/bug-libtool/2015-09/msg00000.html . +# The -i'' is necessary for macOS portability, see https://stackoverflow.com/a/4247319 . +if [ "${CIRRUS_CI}" = "true" ]; then + sed -i'' -e 's@/usr/bin/file@$(which file)@g' ../configure +fi + +../configure \ + --enable-experimental=$EXPERIMENTAL \ + --with-test-override-wide-multiply=$WIDEMUL \ + --with-bignum=$BIGNUM \ + --with-asm=$ASM \ + --enable-ecmult-static-precomputation=$STATICPRECOMPUTATION \ + --with-ecmult-gen-precision=$ECMULTGENPRECISION \ + --enable-module-ecdh=$ECDH \ + --enable-module-multiset=$MULTISET \ + --enable-module-recovery=$RECOVERY \ + --enable-module-schnorr=$SCHNORR \ + --enable-module-schnorrsig=$SCHNORRSIG \ + --enable-jni=$JNI \ + --enable-openssl-tests=$OPENSSL_TESTS \ + --with-valgrind=$WITH_VALGRIND \ + $AUTOTOOLS_EXTRA_FLAGS \ + $USE_HOST + +print_logs() { + cat tests.log || : + cat exhaustive_tests.log || : + cat valgrind_ctime_test.log || : + cat bench.log || : +} +trap 'print_logs' ERR + +make -j2 $AUTOTOOLS_TARGET + +if [ "$RUN_VALGRIND" = "yes" ]; then + # the `--error-exitcode` is required to make the test fail if valgrind found + # errors, otherwise it'll return 0 + # (https://www.valgrind.org/docs/manual/manual-core.html) + valgrind --error-exitcode=42 ./tests 16 + valgrind --error-exitcode=42 ./exhaustive_tests +fi + +if [ -n "$QEMU_CMD" ]; then + $QEMU_CMD ./tests 16 + $QEMU_CMD ./exhaustive_tests +fi + +if [ "$BENCH" = "yes" ]; then + # Using the local `libtool` because on macOS the system's libtool has + # nothing to do with GNU libtool + EXEC='./libtool --mode=execute' + if [ -n "$QEMU_CMD" ]; then + EXEC="$EXEC $QEMU_CMD" + fi + if [ "$RUN_VALGRIND" = "yes" ]; then + EXEC="$EXEC valgrind --error-exitcode=42" + fi + + # This limits the iterations in the benchmarks below to ITER iterations. + export SECP256K1_BENCH_ITERS="$ITERS" + { + $EXEC ./bench_ecmult + $EXEC ./bench_internal + $EXEC ./bench_sign + $EXEC ./bench_verify + } >> bench.log 2>&1 + if [ "$RECOVERY" == "yes" ]; then + $EXEC ./bench_recover >> bench.log 2>&1 + fi + if [ "$ECDH" == "yes" ]; then + $EXEC ./bench_ecdh >> bench.log 2>&1 + fi + if [ "$MULTISET" == "yes" ]; then + $EXEC ./bench_multiset >> bench.log 2>&1 + fi + if [ "$SCHNORRSIG" == "yes" ]; then + $EXEC ./bench_schnorrsig >> bench.log 2>&1 + fi +fi +if [ "$CTIMETEST" = "yes" ]; then + ./libtool --mode=execute valgrind --error-exitcode=42 ./valgrind_ctime_test > valgrind_ctime_test.log 2>&1 +fi + +popd diff --git a/src/secp256k1/ci/build_cmake.sh b/src/secp256k1/ci/build_cmake.sh new file mode 100755 index 000000000..9138ad968 --- /dev/null +++ b/src/secp256k1/ci/build_cmake.sh @@ -0,0 +1,59 @@ +#!/usr/bin/env bash + +export LC_ALL=C + +set -ex + +read -r -a CMAKE_EXTRA_FLAGS <<< "$CMAKE_EXTRA_FLAGS" + +if [ "x$HOST" = "xi686-linux-gnu" ]; then + CMAKE_EXTRA_FLAGS+="-DCMAKE_C_FLAGS=-m32" +fi + +if [ "$RUN_VALGRIND" = "yes" ]; then + CMAKE_C_FLAGS="-DVALGRIND" + if [ "${CIRRUS_OS}" = "darwin" ]; then + # The valgrind/memcheck.h header is not in a standard cmake location when + # installed from the LouisBrunner brew repo, so we need to add it. + #CMAKE_C_FLAGS="-isystem $(brew --prefix valgrind)/include ${CMAKE_C_FLAGS}" + CMAKE_C_FLAGS="-isystem /usr/local/include ${CMAKE_C_FLAGS}" + fi + CMAKE_EXTRA_FLAGS+="-DCMAKE_C_FLAGS=${CMAKE_C_FLAGS}" +fi + +# "auto" is not a valid value for SECP256K1_ECMULT_GEN_PRECISION with cmake. +# In this case we use the default value instead by not setting the cache +# variable on the cmake command line. +if [ "x$ECMULTGENPRECISION" != "xauto" ]; then + ECMULT_GEN_PRECISION_ARG="-DSECP256K1_ECMULT_GEN_PRECISION=$ECMULTGENPRECISION" +fi + +mkdir -p buildcmake/install +pushd buildcmake + +CMAKE_COMMAND=cmake +${CMAKE_COMMAND} --version + +${CMAKE_COMMAND} -GNinja .. \ + -DCMAKE_INSTALL_PREFIX=install \ + -DSECP256K1_BUILD_OPENSSL_TESTS=$OPENSSL_TESTS \ + -DSECP256K1_ECMULT_STATIC_PRECOMPUTATION=$STATICPRECOMPUTATION \ + -DSECP256K1_ENABLE_MODULE_ECDH=$ECDH \ + -DSECP256K1_ENABLE_MODULE_MULTISET=$MULTISET \ + -DSECP256K1_ENABLE_MODULE_RECOVERY=$RECOVERY \ + -DSECP256K1_ENABLE_MODULE_SCHNORR=$SCHNORR \ + -DSECP256K1_ENABLE_MODULE_EXTRAKEYS=$SCHNORRSIG \ + -DSECP256K1_ENABLE_MODULE_SCHNORRSIG=$SCHNORRSIG \ + -DSECP256K1_ENABLE_JNI=$JNI \ + -DSECP256K1_ENABLE_BIGNUM=$BIGNUM \ + -DSECP256K1_USE_ASM=$ASM \ + -DSECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY=$WIDEMUL \ + $ECMULT_GEN_PRECISION_ARG \ + "${CMAKE_EXTRA_FLAGS[@]}" + +# This limits the iterations in the benchmarks below to ITER iterations. +export SECP256K1_BENCH_ITERS="$ITERS" + +ninja $CMAKE_TARGET + +popd diff --git a/src/secp256k1/ci/linux-debian-s390-qemu.Dockerfile b/src/secp256k1/ci/linux-debian-s390-qemu.Dockerfile new file mode 100644 index 000000000..52aa6c865 --- /dev/null +++ b/src/secp256k1/ci/linux-debian-s390-qemu.Dockerfile @@ -0,0 +1,8 @@ +FROM debian:buster + +RUN dpkg --add-architecture s390x +RUN echo "deb http://deb.debian.org/debian buster-backports main" | tee -a /etc/apt/sources.list +RUN apt-get update +RUN apt-get install --no-install-recommends --no-upgrade -y automake libtool make ninja-build python3 +RUN apt-get install --no-install-recommends --no-upgrade -y gcc-s390x-linux-gnu libc6-dev-s390x-cross libc6:s390x qemu-user +RUN apt-get install -t buster-backports --no-install-recommends --no-upgrade -y cmake diff --git a/src/secp256k1/ci/linux-nixos.Dockerfile b/src/secp256k1/ci/linux-nixos.Dockerfile new file mode 100644 index 000000000..0017073c9 --- /dev/null +++ b/src/secp256k1/ci/linux-nixos.Dockerfile @@ -0,0 +1,12 @@ +FROM nixos/nix + +COPY ci/shell.nix /tmp +COPY ci/shell-i686.nix /tmp + +RUN nix-channel --remove nixpkgs +RUN nix-channel --add https://nixos.org/channels/nixos-20.09 nixpkgs +RUN nix-channel --update + +# Run dummy command "true" in the nix-shell just to get the packages prepared. +RUN nix-shell /tmp/shell.nix --command true +RUN nix-shell /tmp/shell-i686.nix --command true diff --git a/src/secp256k1/ci/shell-i686.nix b/src/secp256k1/ci/shell-i686.nix new file mode 100644 index 000000000..38f48c3e8 --- /dev/null +++ b/src/secp256k1/ci/shell-i686.nix @@ -0,0 +1,12 @@ +{ pkgs ? (import {}).pkgsi686Linux }: + +with pkgs; + +mkShell { + buildInputs = [ + autoconf automake bash clang cmake file gcc gmp libtool ninja pkgconfig python3 valgrind + ]; + shellHook = '' + echo Running nix-shell with nixpkgs version: $(nix eval --raw nixpkgs.lib.version) + ''; +} diff --git a/src/secp256k1/ci/shell.nix b/src/secp256k1/ci/shell.nix new file mode 100644 index 000000000..fd1f801d2 --- /dev/null +++ b/src/secp256k1/ci/shell.nix @@ -0,0 +1,12 @@ +{ pkgs ? import {} }: + +with pkgs; + +mkShell { + buildInputs = [ + autoconf automake bash clang cmake file gcc gmp jdk11_headless libtool ninja openssl pkgconfig python3 valgrind + ]; + shellHook = '' + echo Running nix-shell with nixpkgs version: $(nix eval --raw nixpkgs.lib.version) + ''; +}